【入門編】厳格モード(use strict)が変数の暗黙的宣言を許さない技術的理由 – JavaScriptコア文法・モダン言語仕様と変数・関数解析バイブル

こんにちは!フロントエンドからNode.jsの深部まで、日夜JavaScriptと向き合っているシニアアーキテクトです。

今回は、JavaScriptの基礎中の基礎でありながら、実はV8エンジンの最適化やセキュリティの根幹に関わる非常に重要なテーマ「厳格モード(`use strict`)が変数の暗黙的宣言を許さない技術的理由」について、深く掘り下げてお話ししていきますね。

「JavaScriptを書き始めたばかりの頃、うっかり変数宣言の `let` や `const` を書き忘れても動いちゃったな……」なんて経験はありませんか? 実は、あの「こっそりグローバル変数を作ってしまう仕様」こそが、大規模開発やパフォーマンスチューニングにおいて悪夢を引き起こす元凶なんです。

ここをしっかりクリアすれば、JavaScriptのランタイムが裏側でどう動いているのかが見えてきて、コードの質がワンランクもツーランクも上がりますよ。それでは、一緒に紐解いていきましょう!

—

1. 「暗黙のグローバル変数」が引き起こすカオス

まずは、JavaScriptの歴史が生んだ最も危険な仕様「暗黙のグローバル変数(Implied Globals)」について見ていきましょう。

普段、私たちは変数を宣言するときに `let` や `const`(古いコードでは `var`)を使いますよね。しかし、これらを付けずに値を代入するとどうなるでしょうか?

// strictモードを使わない( sloppy mode )環境でのコード
function calculateTotal() {
// 意図せず let や const を書き忘れた!
totalAmount = 1000 1.15;
return totalAmount;
}

calculateTotal();

// 関数が実行された後なのに……
console.log(totalAmount); // なぜか 1150 が出力されてしまう!

このコード、何が起きているか分かりますか? `totalAmount` という変数はどこで宣言されたわけでもありません。しかし、JavaScriptエンジンは「おっと、宣言されていない名前だな? ならばグローバルオブジェクト(ブラウザなら `window`、Node.jsなら `global`)のプロパティとして勝手に生やしてやろう!」と解釈してしまいます。

これが暗黙のグローバル変数です。

なぜこれが危険なのか?

1. スペルミスがバグとして検知されない
`userAnme = “John”;` と打つつもりが `userName = “John”;` とタイポしても、エラーが出ずに大域空間にゴミが生成されます。
2. スコープの汚染と予期せぬ上書き
別のファイルやライブラリでたまたま同じ変数名が使われていた場合、お互いの値が意図せず書き換えられ、原因究明が極めて困難なバグ(いわゆる「名前空間の衝突」)に繋がります。

—

2. 厳格モード(`use strict`)による「セーフティネット」

こうしたJavaScriptの「優しすぎる(=危険すぎる)仕様」をバッサリと切り捨て、エラーとして検知できるようにするために導入されたのが、ES5で追加された厳格モード(Strict Mode)です。

使い方は簡単。ファイルの先頭、または関数の先頭に `”use strict”;` と記述するだけです。

“use strict”;

function calculateTotal() {
// 変数宣言なしで代入を試みる
totalAmount = 1000 1.15; // ここで即座にReferenceErrorが発生!
return totalAmount;
}

calculateTotal();

厳格モードを有効にした状態で先ほどのコードを実行すると、JavaScriptエンジンは容赦なく `ReferenceError: totalAmount is not defined` を投げます。

「エラーが出るなんて怖くない?」と思われるかもしれませんが、開発者にとって「バグが隠蔽されずに、その場で即座にエラーとして教えてもらえる」というのは最高の幸運です。未然に致命傷を防いでくれる、強力なセーフティネットとして機能してくれます。

—

3. ここが本質:なぜエンジンは暗黙の宣言を許さないのか?(V8の視点)

さて、ここからがエンジニアとしての醍醐味です。なぜ、厳格モードはこれほどまでに「変数の暗黙的宣言」を厳しく制限するのでしょうか? それは、JavaScriptエンジン(Google ChromeのV8など)のメモリ最適化と実行速度に決定的な悪影響を与えるからです。

少し裏側の話をしましょう。

① 「ハッシュマップ」への退化(インラインキャッシュの崩壊)

現代のJavaScriptエンジンは、コードを爆速で実行するために「隠れクラス(Hidden Classes / Shapes)」や「インラインキャッシュ(Inline Caches)」という高度な最適化テクニックを使っています。オブジェクトのプロパティがどこにあるかをメモリ上の固定オフセットで記憶し、C言語並みのスピードでアクセスできるようにしているのです。

しかし、暗黙のグローバル変数が発生すると、グローバルオブジェクト(`window` や `global`)に対して動的に次々と新しいプロパティが追加されることになります。
これは、エンジンにとって「いつでもプロパティの構造が変化する、予測不可能なハッシュマップ(連想配列)」を扱わされているのと同じ状態です。結果として、エンジンは高速化の最適化を諦めざるを得なくなり、コード全体の実行パフォーマンスがガクッと落ちてしまいます。

② 静的解析(Linterやトランスパイラ)の限界

変数宣言が明示されていると、WebpackやBabel、TypeScript、あるいはモダンなIDE(VS Codeなど)は、コードの依存関係やスコープを「静的(ソースコードを読んだだけ)」に解析できます。
しかし、動的にグローバル空間へ突撃するコードがあると、スコープチェーンの境界が曖昧になり、高度な最適化やツリーシェイキング(不要なコードの削除)が正常に働かなくなります。

つまり、`use strict` は単なる文法上のルールではなく、「V8エンジンに全力で高速化の仕事をさせるための契約書」でもあるのです。

—

4. 現代のJavaScript開発における事実上の標準

「じゃあ、毎回ファイルの一番上に `”use strict”;` って書かなきゃいけないの?」と思われるかもしれませんが、安心してください。

私たちが普段現場で使っているモダンな開発環境(ES Modules、TypeScript、Babel、ReactやVueなどのフレームワーク)では、デフォルトで厳格モードが強制されています。

例えば、現代のJSの基本単位である ES Modules (`

シェアする
javascriptintronationalをフォローする
タイトルとURLをコピーしました