まず「暗黙的なグローバル」を一言でいうと
暗黙的なグローバルは、
「自分ではグローバル変数を作ったつもりがないのに、“こっそり”グローバル変数が作られてしまう現象」
のことです。
もっと砕くと、
本当は let / const / var で宣言しなきゃいけないのに
それを忘れて、いきなり名前に代入してしまった結果、
勝手にグローバル変数ができてしまう
これが「暗黙的(あんもくてき)なグローバル」です。
ここが重要です。
「宣言をサボると、勝手にグローバル変数が増える」
という、初心者がハマりやすい危険な挙動が JavaScript にはある(あった)
という話です。
暗黙的なグローバルがどうやって生まれるか
最も典型的なパターン:宣言を忘れた代入
まず問題のコードを見てください(ブラウザ・非 strict mode 想定)。
function doSomething() {
x = 10; // ← let / const / var を付けていない
}
doSomething();
console.log(x); // 10 と表示されてしまう
JavaScript本来なら、
function doSomething() {
let x = 10;
}
JavaScriptのように let か const で宣言すべきところを、
うっかり書き忘れて x = 10; と書いたとします。
このとき JavaScript は、
「x という変数がどこにも宣言されていないな…
じゃあ グローバルオブジェクト(window など)のプロパティとして新しく作ってしまおう」
という挙動をします(非 strict mode の場合)。
結果として、
doSomething の中でしか使うつもりのなかった x が
「グローバルな変数 x」として勝手に作られてしまう のです。
何がまずいのか
この挙動の何が怖いかというと、
本当はローカル変数のつもりで書いたのに、
気づかないうちにグローバル変数が増えている
という点です。
さらに、グローバルには同じ名前の変数が他にも存在するかもしれません。
let x = 1; // もともとのグローバル
function doSomething() {
x = 10; // 宣言を忘れている → グローバル x を上書きしてしまう
}
JavaScript「ここでちょっとだけ使うつもりの x」のつもりが、
他の処理でも使っていた x を壊してしまう 可能性があります。
ここが重要です。
「宣言忘れ」で暗黙的なグローバルが生まれると、変数の意図しない上書き・予期しない共有が起きる。
バグの原因がとても見つけにくい形で潜むことになる。
ブラウザでのイメージ:window に勝手にプロパティが生える
実際にどうなるか見てみる
ブラウザのコンソールで、次のように打ってみると分かりやすいです(非 strict mode)。
function foo() {
y = 123; // 宣言しないで代入
}
foo();
console.log(y); // 123
console.log(window.y); // 123
JavaScripty を宣言していないのに、window.y というプロパティができています。
これは、
「宣言されていない識別子に代入があった場合、
グローバルオブジェクト(ブラウザなら window)のプロパティとして追加する」
という挙動によるものです。
つまり、
y = 123;
は実質的に
window.y = 123;
と同じ意味になってしまっています。
意図しない「共有状態」が生まれる
window は「ブラウザ全体の共有スペース」です。
ここに勝手に y が増えると、
別のスクリプトからも y が見えてしまう ことになります。
他ファイル・他ライブラリのコードと名前が被ると、
「誰かがどこかで y を上書きしてしまった」
ということが起こり得ます。
「自分はそんなつもりじゃなかったのに、勝手に共同スペースに変数を置いてしまっていた」というのが、暗黙的なグローバルの厄介なところです。
strict mode ではどうなるか(暗黙的なグローバルはエラーになる)
“use strict” を使うと、宣言忘れは即エラー
暗黙的なグローバルが危険すぎるため、
JavaScript には strict mode という「厳しいモード」が用意されています。
ファイルや関数の先頭に、
"use strict";
JavaScriptと書くと、そのスコープ内では、
「宣言していない変数に代入する」
という行為が、即エラー になります。
"use strict";
function doSomething() {
x = 10; // ここで ReferenceError: x is not defined
}
doSomething();
JavaScript暗黙的なグローバルを勝手に作る代わりに、
「お前、宣言忘れてるぞ」と怒ってくれる わけです。
ここが重要です。
strict mode(やモジュール)では、「宣言していない変数に代入する」=バグ確定とみなされる。
そのおかげで、暗黙的なグローバルの多くは早い段階で潰せる。
ESモジュール(<script type="module"> や import/export)では自動で厳しめ
ブラウザで <script type="module"> を使ったり、
Node.js で ES モジュールを使っている場合、
自動的に strict mode 相当の挙動になります。
つまり、モジュール前提の書き方をしていれば、
そもそも暗黙的なグローバルは作られにくくなっています。
とはいえ、「宣言していない変数を使うとエラー」という感覚自体は、
初心者のうちからしっかり持っておいたほうがよいです。
暗黙的なグローバルを避けるための基本ルール
1: 必ず let / const / var で宣言する
一番大事なルールは、これだけです。
「変数を使う前に、必ず let / const / var で宣言する」
// 悪い例
function bad() {
count = 0; // 宣言なし → 暗黙的なグローバル
}
// 良い例
function good() {
let count = 0; // 宣言あり → ローカル変数
}
JavaScript特に、for や if の中で、
つい
for (i = 0; i < 10; i++) {
...
}
JavaScriptのように書いてしまうのは危険です。
必ずこう書く癖をつける:
for (let i = 0; i < 10; i++) {
...
}
JavaScript2: linter やエディタの警告を活用する
ESLint などのツールや、VS Code のようなエディタは、
「宣言されていない変数を使っている」
ことをちゃんと警告してくれます。
初心者ほど、そういう「怒ってくれるツール」に頼るべき です。
「赤線が出たら必ず直す」「宣言が見当たらない変数は怪しむ」
という習慣がつけば、暗黙的なグローバルはほぼ防げます。
3: グローバルをどうしても使うなら、明示的に書く
どうしてもグローバルな場所に変数を置きたい場合、
少なくとも「暗黙的に」ではなく、明示的に やるべきです。
// 悪い
function setup() {
config = { theme: "dark" }; // 暗黙的なグローバル
}
// 良い(まだ危ういが、意図は明示されている)
window.config = { theme: "dark" };
JavaScript後者なら、
「ここでグローバル(window)に config を生やしているんだな」と意識できます。
根本的には、前の話のように
「グローバル変数をそもそも減らしていく」ことが大事ですが、
どうせ使うなら“暗黙的”ではなく“意図的”に使う というのが最低ラインです。
ここが重要です。
暗黙的なグローバルが危険なのは、「どこで作られたか自分でも気づきにくい」から。
宣言を徹底し、必要なグローバルは明示的に扱うことで、“勝手に増えるグローバル”をなくすのが目標。
初心者としての「暗黙的なグローバル」の押さえどころ
最後に、このテーマで本当に大事なポイントだけまとめます。
暗黙的なグローバルとは、「宣言していない変数に代入した結果、勝手にグローバル変数が作られてしまう現象」。
原因は、let / const / var を付け忘れて、いきなり x = ... と書いてしまうこと。
非 strict mode では、それが window.x = ... のように解釈され、グローバルに生えてしまう。
暗黙的なグローバルがあると、
どこで変数が作られたか分かりにくく、
意図しない上書き・共有が起きてバグの原因になる。
strict mode や ESモジュールでは、宣言していない変数への代入はエラーになるので、暗黙的なグローバルは起きにくくなる。
対策としては、
- 必ず
let/const(必要ならvar)で宣言してから使う - エディタや linter の警告を無視しない
- グローバルを使う場合も、暗黙ではなく明示的に扱う
ここが重要です。
「宣言しない変数は絶対に使わない」
この感覚さえ身体に染み込めば、暗黙的なグローバルという厄介なバグの温床を、かなりの確率で回避できます。
もしよければ、意識的に
function test() {
value = 42;
}
test();
console.log(value);
JavaScriptのようなコードを一度書いてみて、
「strict mode あり/なしでどう挙動が違うか」を確かめてみてください。
自分の目で「勝手にグローバルになってしまう瞬間」と
「strict mode で怒られる瞬間」を体験すると、
「宣言をサボる怖さ」が一気にリアルに感じられるはずです。
