こんにちは!フロントエンドからNode.jsの深層まで、日夜JavaScriptと向き合っているあなたの専属先輩エンジニアです。
今回は、JavaScriptの基本中の基本でありながら、実はV8エンジンの内部挙動やパフォーマンス、そしてセキュリティにまで深く関わる「変数宣言と厳格モード(`use strict`)」の真実についてお話しします。
「たかが `var`, `let`, `const` の話でしょ?」と思っていませんか?
ここをクリアすれば、JavaScriptのランタイムが裏側でどう動いているのかが見え、ワンランク上のエンジニアへと一気にステップアップできますよ。それでは、さっそく本質を紐解いていきましょう!
—
1. そもそも「変数の暗黙的宣言」ってなに?
JavaScriptには、歴史的な経緯から生まれた「危うい仕様」が存在します。それは、`let` や `const`、あるいは古の `var` すら使わずに、いきなり値を代入することで変数を作れてしまうという挙動です。
まずは以下のコードを見てください。
// 関数の中で、宣言なしに変数を使い始める
function calculateTotal() {
// 宣言キーワード(let / const)がない!
taxRate = 0.10;
subtotal = 5000;
return subtotal (1 + taxRate);
}
console.log(calculateTotal()); // 5500 と表示される
「あれ? エラーにならずに動いたよ?」と思いましたよね。
一見すると便利に見えるこの挙動ですが、これがJavaScriptの歴史において数々のバグを生み出してきた「暗黙のグローバル変数(Implied Globals)」と呼ばれる悪夢の元凶です。
実はこのコードを実行すると、`taxRate` と `subtotal` はローカル変数ではなく、グローバルオブジェクト(ブラウザなら `window`、Node.jsなら `global`)のプロパティとして勝手に登録されてしまいます。
つまり、関数の中でこっそり定義したつもりが、アプリケーション全体のどこからでも書き換え可能なグローバル変数として野放しになってしまうのです。これは保守性の観点から見ても、セキュリティの観点から見ても非常に危険な状態ですよね。
—
2. なぜ `use strict`(厳格モード)が必要なのか?
こうしたJavaScriptの「優しすぎる(=危険な)仕様」をバッサリと切り捨て、エラーとして検知できるようにして moderne な構文規則を強制するのが `use strict`(厳格モード) です。
ファイルの先頭、あるいは関数の先頭に `”use strict”;` と記述するだけで、JavaScriptエンジンは「厳格モード」でコードを解釈し始めます。
“use strict”;
function calculateTotal() {
// 宣言なしで代入してみる
taxRate = 0.10; // 💥 ここで即座に ReferenceError が発生!
let subtotal = 5000;
return subtotal (1 + taxRate);
}
calculateTotal();
厳格モード下で暗黙的に変数を宣言しようとすると、JavaScriptエンジンは容赦なく `ReferenceError: taxRate is not defined` という実行時エラーを投げます。
「エラーになるなんて面倒だな」と感じるかもしれませんが、これは「バグが潜んでいることを、プログラムが実行された瞬間に教えてくれる最高のセーフティネット」なのです。気づかずにグローバル空間を汚染してしまうバグに比べれば、エラーで止まってくれた方が何倍もありがたいですよね。
—
3. V8エンジンの視点:なぜ「暗黙的宣言」は最適化をブチ壊すのか?
ここからが少しディープなお話です。私たちを支えるJavaScriptエンジン(Google ChromeやNode.jsで使われている V8 など)は、コードを高速に実行するために裏側で凄まじい最適化を行っています。
ここで、V8エンジンの気持ちになって考えてみましょう。
隠しクラス(Hidden Class)とインラインキャッシュ
V8は、オブジェクトのプロパティ構造を効率よく管理するために「隠しクラス」という仕組みを使っています。変数が「どこに存在し、どんな型なのか」が事前にわかっていれば、メモリ上のオフセット(番地)を直接叩いて高速にアクセスできます。
しかし、先ほどのような「暗黙的グローバル変数」はどうでしょう?
コードの実行中に、予期せぬタイミングで `window` オブジェクトに新しいプロパティがポコッと生えてきます。
// どこかの関数で突然生まれる暗黙的グローバル変数
function foo() {
unexpectedGlobal = 42;
}
これを見たV8エンジンはこう叫びます。
> 「おいおい! グローバルオブジェクトの構造が実行中に勝手に書き換わったぞ! 今まで組み立ててきたメモリの最適化プランが全部パーだ! いちいちプロパティの検索をし直さなきゃいけないじゃないか……!(スローダウン)」
このように、暗黙的変数の存在は、V8がコードを高速に機械語へコンパイル(JITコンパイル)する際の強力な最適化の芽を完全に摘んでしまうのです。
コンパイル時最適化へのシフト
`use strict` を宣言し、すべての変数が `let` や `const` によってスコープ(生存期間と可視範囲)を明確に定義されると、V8エンジンは次のような恩恵を受けられます。
1. スコープの静的解析: 変数がどのスコープに属しているかがコンパイル時に完全に特定できるため、不要になったメモリを即座にガベージコレクション(GC)の対象にできる。
2. メモリレイアウトの固定: 変数の置き場所が最適化され、プロパティルックアップのオーバーヘッド(遅延)が消滅する。
つまり、`use strict` は単なる「コーディングのルール」ではなく、V8エンジンという超高性能なランタイムのエンジンをフル回転させるための「入場チケット」なのです。
—
4. 陥りやすい文法エラーと、現代のJavaScriptにおけるベストプラクティス
初心者の方がよくやってしまうミスとして、以下のようなものがあります。
“use strict”;
// ❌ ありがちなミス:変数のつづり間違い
let userAge = 25;
// うっかり大文字・小文字を間違えて代入してしまう
usreAge = 26; // ReferenceError: usreAge is not defined
`use strict` を使っていなければ、意図せず `usreAge` という新しいグローバル変数が作られてしまい、「あれ? `userAge` が更新されないぞ……?」という何ともシュールなバグに数時間悩まされることになります。厳格モードであれば、即座にタイポ(入力ミス)を指摘してくれます。
現代の開発環境におけるベストプラクティス
もっと言えば、現代のモダンなJavaScript開発(ES Modulesや、Babel / TypeScript / Vite などのビルドツールを通した環境)では、デフォルトで自動的に厳格モードが適用されるようになっています。
そのため、普段意識して `”use strict”;` と書く機会は減っているかもしれませんが、その裏で「なぜエラーになるのか」「なぜ宣言が必須なのか」というV8の仕組みを知っているかいないかで、書くコードの質やパフォーマンスに対する意識は劇的に変わります。
—
まとめ:ここをクリアすれば、JSの基本はバッチリ!
- 暗黙的グローバル変数は、意図しないスコープ汚染やセキュリティリスクを生む。
- `use strict`(厳格モード)は、そうした曖昧な記述を即座にエラーとして検知し、バグを未然に防ぐ。
- V8エンジンなどのランタイムにとって、変数の宣言が明確であることは、メモリ最適化と高速なJITコンパイルを引き出すために不可欠である。
変数を宣言するときは、常に `const`(基本)と `let`(再代入が必要な場合のみ)を使い、うっかり屋さんのJavaScriptに甘えない堅牢なコードを書いていきましょう。
ここをしっかりと理解できたあなたなら、もう変数やスコープの挙動で迷うことはありません。自信を持って次のステップへ進んでくださいね!