【実務・中級編】なぜ現代のJavaScript開発でvarを禁止すべきなのか:スコープ汚染が引き起こすバグの再現実験 – JavaScriptコア文法・モダン言語仕様と変数・関数解析バイブル

エンジニアの皆さん、コードレビューの場で「なぜまだ `var` を使っているのか?」と問いただす側になっていないだろうか。

現代のJavaScript開発において、`var` の使用は百害あって一利なしだ。ES2015(ES6)の黎明期から幾度となくその非道性が叫ばれてきたにもかかわらず、いまだにレガシーなコードベースや、表面的な理解のまま書かれたスクリプトの中には `var` の残骸が息を潜めている。

今回は、V8エンジンのメモリモデルと実行コンテキストの挙動にまで踏み込み、なぜ `var` が現代の開発において「悪」であり、直ちに撲滅されなければならないのかを、実務的なコードの実験を通してロジカルに解き明かしていく。

—

1. 実行コンテキストと変数ホイスティングの闇

まず、JavaScriptエンジン(V8など)がコードを解釈し、実行するメカニズムの根本から振り返ろう。JavaScriptはインタプリタ言語のように見えて、実際には実行前に「Creation Phase(生成フェーズ)」と「Execution Phase(実行フェーズ)」という2つのステップを経る。

この生成フェーズにおいて、`var` で宣言された変数は、そのスコープの最上部に「巻き上げ(Hoisting)」され、自動的に `undefined` で初期化される。

console.log(userId); // エラーにならず、”undefined” が出力される
var userId = ‘EMP-8842’;
console.log(userId); // “EMP-8842”

これの何が問題か。言語仕様上、「宣言される前に変数がアクセス可能(ただし値は `undefined`)」という、人間心理に反する挙動を許容してしまうことだ。大規模な非同期処理や複雑なコンポーネントのライフサイクルにおいて、この挙動は「存在しないはずのデータが参照できてしまう」という致命的な論理バグ(Silent Failure)の温床となる。

TDZ(Temporal Dead Zone)という福音

一方、`let` や `const` も巻き上げは起きる。しかし、これらは生成フェーズで初期化を行わない。宣言の行に到達するまでの間、その変数は「時間的デッドゾーン(TDZ)」に置かれ、アクセスしようものなら即座に `ReferenceError` がスローされる。

console.log(apiKey); // ReferenceError: Cannot access ‘apiKey’ before initialization
let apiKey = ‘secret_fx9902’;

バグは「隠蔽される」よりも「即座にクラッシュして教えтеくれる」方がはるかに安全である。`let` と `const` は、言語レベルでバグを早期発見させるための防壁なのだ。

—

2. スコープ汚染の実験:なぜ `var` は関数を突き抜けるのか

`var` の最大にして最悪の特性は、それが「関数スコープ」しか持たない点にある。`if` 文や `for` ループといった、いわゆるブロック( `{}` )を完全に無視して外側に漏れ出す。

以下の実務さながらのデータ処理パイプラインのコードを見てほしい。

/