JavaScript | 基礎構文:変数・定数 – 暗黙的なグローバル

JavaScript
スポンサーリンク

まず「暗黙的なグローバル」を一言でいうと

暗黙的なグローバルは、
「自分ではグローバル変数を作ったつもりがないのに、“こっそり”グローバル変数が作られてしまう現象」
のことです。

もっと砕くと、

本当は 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

のように letconst で宣言すべきところを、
うっかり書き忘れて 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
JavaScript

y を宣言していないのに、
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

特に、forif の中で、
つい

for (i = 0; i < 10; i++) {
  ...
}
JavaScript

のように書いてしまうのは危険です。

必ずこう書く癖をつける:

for (let i = 0; i < 10; i++) {
  ...
}
JavaScript

2: 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 で怒られる瞬間」を体験すると、
「宣言をサボる怖さ」が一気にリアルに感じられるはずです。

タイトルとURLをコピーしました