【入門編】厳格モード(use strict)が変数の宣言に与える強制力:暗黙のグローバル変数生成を阻止する – JavaScriptコア文法・モダン言語仕様と変数・関数解析バイブル

こんにちは!フロントエンドからNode.jsの深部まで、JavaScriptの生態系をくまなく見つめてきたチーフアーキテクトの私です。

皆さんは日々のコーディングで `use strict`(厳格モード)を意識していますか?「なんとなくおまじないとして書いている」「Linterが怒るから入れている」という方も多いかもしれませんね。

しかし、この小さな一行の有無が、JavaScriptという言語の挙動を根底から変えてしまうとしたらどうでしょう?特に「変数の宣言」において、`use strict` は私たちのコードを予期せぬバグから守る最強の盾となります。

ここをクリアすれば、JavaScriptの変数スコープとランタイムの挙動に関する基本はバッチリマスターできますよ。さあ、その知見の扉を開いていきましょう。

—

1. そもそも「変数の宣言漏れ」で何が起きていたのか?

JavaScriptを学び始めたばかりの頃、うっかり `let` や `const`、あるいは古いコードの `var` を書き忘れて、次のように変数に値を代入してしまったことはありませんか?

function calculateTotal() {
// 宣言キーワード(let/const)を書き忘れた!
total = 1000;
return total 1.1;
}

calculateTotal();
console.log(total); // 1000 と出力されてしまう…あれ?

他の厳格なプログラミング言語(JavaやC#など)であれば、ここで「変数 `total` が宣言されていません」とコンパイルエラーになりますよね。

しかし、従来のJavaScript(非厳格モード)は非常に寛容(すぎる)でした。なんと、このコードを実行すると、エラーになるどころか、勝手にグローバルオブジェクト(ブラウザなら `window`、Node.jsなら `global`)のプロパティとして `total` を新しく作り出してしまうのです。

これが、悪名高い「暗黙のグローバル変数(Implied Global)」の生成です。

恐ろしいバグの温床:タイポが生む悲劇

この仕様がどれほど危険か、想像がつくでしょうか。例えば、次のようなケースです。

let userCount = 10;

function updateCount() {
// 本来は userCount を書き換えたいのに、うっかり ‘c’ を抜かしてタイポした!
userCout = 20;
}

updateCount();

console.log(userCount); // 10 (あれ?変わってない)
console.log(global.userCout); // 20 (なんと、意図せずグローバル変数が生えてしまった!)

プログラムが巨大化し、ファイルの分割やモジュール化が進む現代において、意図しないグローバル変数が勝手に生成されるのは、デバッグ不可能なバグの温床になります。どこからでも書き換え可能な変数がグローバル空間にばらまかれ、変数名の衝突(ネームスペースの汚染)を引き起こすからです。

—

2. 救世主 `use strict`(厳格モード)の登場

こうしたJavaScriptの「緩すぎる歴史的負債」を断ち切り、より堅牢で予測可能なコードを書くためにECMAScript 5で導入されたのが `use strict`(厳格モード) です。

使い方は極めてシンプル。ファイルや関数の先頭に文字列として記述するだけです。

“use strict”;

function secureCalculate() {
// 変数の宣言漏れがあると……?
strictTotal = 1000; // 💥 ここで即座にエラー発生!
return strictTotal 1.1;
}

secureCalculate();

このコードを実行すると、V8などのJavaScriptエンジンは次のようなReferenceError(参照エラー)を投げます。

ReferenceError: strictTotal is not defined

「おっと、君は `let` や `const` で変数を作っていないのに、いきなり値を代入しようとしているね? そんな危険なことはさせないよ!」と、ランタイムが厳格にストップをかけてくれるのです。

—

3. なぜ `use strict` はエラーにできるのか?(言語仕様とランタイムの裏側)

ここから少しだけ、JavaScriptエンジン(V8など)の内部で何が起きているのか、エンジニアの視点で少し深く覗いてみましょう。

JavaScriptの仕様(ECMAScript Specification)において、コードの実行は「Strict Mode Code」と「Non-strict Mode Code」に厳密に分類されます。

1. 非厳格モードの場合:
識別子への代入(Assignment Expression)に遭遇した際、現在のスコープチェーンを遡ってもその変数がどこにも見つからない場合、JavaScriptエンジンは「ああ、グローバルオブジェクトにその名前のプロパティを追加したいんだな」と親切心(お節介)から解釈し、グローバルオブジェクト上に暗黙的にプロパティを動的生成します。
2. 厳格モード(`use strict`)の場合:
識別子の解決に失敗した瞬間、エンジンはその親切心を完全に封印します。仕様書に定められたルールに従い、「未宣言の識別子への代入は、即座に ReferenceError をスローしなければならない」という鉄の掟を執行するのです。

このチェックはランタイムのパース・実行フェーズの極めて初期に行われるため、タイポによるバグが本番環境のユーザーのブラウザ上で沈黙したまま実行されるのを未然に防ぎます。

—

4. 現代のJavaScript開発における `use strict`

「でも、最近は Babel や TypeScript、あるいは Vite のようなモダンなバンドラを使っているから、自分であえて `”use strict”;` なんて書いたことないよ?」という方もいらっしゃるでしょう。

その通りです。現代のフロントエンド開発において、私たちが書くコードは多くの場合、ES Modules(ESM)として扱われたり、ビルドツールによって自動的にモジュールスコープに変換されたりします。

実は、ES Modulesの内部や、クラス(Class)の構文の内部では、明示的に `”use strict”;` と書かなくても、自動的に厳格モードが適用されるという仕様になっています。

しかし、だからといって「知らなくていい知識」ではありません。
レガシーなスクリプトファイルに手を加える時や、Node.jsのプレーンなCommonJS環境(`require`を使う環境)でスクリプトを書く際、あるいは独自の小さなユーティリティ関数をサクッと書く際には、自ら `”use strict”;` を宣言する習慣が身を守る大きな武器になります。

—

まとめ:今日から使えるベストプラクティス

変数の宣言とスコープにおける `use strict` の強制力、その本質がお分かりいただけたでしょうか?

  • 暗黙のグローバル変数の生成を防ぐ:タイポによるバグやグローバル汚染を根絶する。
  • エラーを早期に検知する:サイレントエラーに悩まされる時間をゼロにし、開発効率を爆上げする。

JavaScriptという言語の足場を固め、より安全で信頼性の高いコードベースを構築するために、変数は必ず `let` や `const` で宣言し、必要に応じて厳格モードの恩恵をしっかりと受けていきましょう。

ここをクリアしたあなたなら、もう変数周りの挙動で迷うことはありません。自信を持って、次のステップへ進んでください!

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