「巻き上げ」の裏側を知れば、JavaScriptはもっと怖くない。TDZ(一時的死域)との付き合い方
こんにちは。今日はJavaScriptの「巻き上げ(Hoisting)」と「一時的死域(TDZ)」について話をしよう。
中級レベルに差し掛かると、`var`を捨てて`let`や`const`を使うのは当たり前になる。だが、なぜ`let`や`const`を使うのかと聞かれたとき、「再代入できないから」「スコープが綺麗だから」という理由だけで止まっていないだろうか?
実は、「なぜ初期化前にアクセスすると死ぬのか」というブラウザの内部挙動まで理解しておくと、現場でのデバッグ速度が一段階変わる。今日は、仕様書に書かれた堅苦しい記述ではなく、フロントエンドの現場で生き残るための「エンジニアの視点」で語らせてもらうよ。
—
1. そもそも「巻き上げ」をどう捉えるか
`var`を使っていた頃の「巻き上げ」は、宣言そのものがスコープの先頭に移動し、`undefined`で初期化されるという仕様だった。しかし、`let`や`const`が登場してからは、この概念が少し複雑になった。
結論から言うと、`let`や`const`も実は巻き上げられている。
だが、`var`のように「よしなに`undefined`を入れておいてくれる」という甘いお膳立てはしてくれない。ここが重要だ。
2. TDZ(一時的死域)という「禁断の領域」
`let`や`const`で宣言された変数は、スコープに入ってから実際の宣言行に到達するまでの間、「存在はしているが、触ると即死する」という状態になる。これがTDZ(Temporal Dead Zone:一時的死域)だ。
ブラウザのエンジン(V8など)は、この領域を「変数へのアクセスが許可されていない期間」として厳格に管理している。この期間中にアクセスしようとすると、例外なく `ReferenceError` が飛ぶ。これはJavaScriptが、「宣言する前に使おうとする不届きなコード」を未然に排除するための強力な防波堤なんだ。
以下のコードで確認してみよう。
// ———————————————————
// TDZの挙動を体感する実験コード
// ———————————————————
{
// ここから下の「a」の宣言行までがTDZ
// console.log(a); // ここでReferenceErrorが発生!
const a = “私はTDZを抜けた後にしか存在しない”;
console.log(a); // ここなら安全にアクセスできる
}
// 関数の引数も、実はTDZの影響を受けることがある
function example(arg = b) { // bはまだ宣言されていないのでTDZ内
const b = 10;
return arg;
}
// example(); // ReferenceError: Cannot access ‘b’ before initialization
3. 実務でなぜ「TDZ」を気にする必要があるのか?
「いやいや、そんな宣言前に変数を使うようなコード、普通書かないでしょう?」と思うかもしれない。だが、現場のコードはもっと複雑だ。
特に多い事故が、クロージャやコールバック内での早期参照だ。
// 実務でよくある事故のパターン
const setup = () => {
// 初期化ロジック
const config = { api: “https://api.example.com” };
// 意図せずクロージャ内で宣言前に参照してしまうケース
const fetchData = () => {
console.log(config.api);
};
// もしここで `const config` が何らかの理由で
// setupの先頭で定義されていなかったら?
// 複雑な依存関係の中で、初期化順序がズレると一瞬で落ちる。
};
TDZを意識する最大のメリットは、「変数のライフサイクル」を意識してコードを書く癖がつくことだ。宣言はスコープの先頭にまとめる、あるいは「使う瞬間に定義する」という原則を徹底するだけで、バグの温床を一つ潰せる。
4. シニアアーキテクトからのアドバイス
TDZは、JavaScriptが「動的型付け言語」という自由奔放な性格から、「大規模開発にも耐えうる堅牢な言語」へと進化するための制約なんだ。
1. 宣言は常にスコープの最上部で行うか、`const`を使って初期化と同時に定義する。
2. `var`は過去の遺物として封印する。(`var`の巻き上げの甘さは、予期せぬバグの温床でしかない)
3. 「ReferenceError」が出たら、「あ、今TDZに触れてしまったな」と冷静にスタックトレースを見る。
TDZは怖くない。むしろ、あなたのコードが正しく動くことを保証してくれる「番人」だと思ってほしい。この挙動を理解しているだけで、コードレビューの質も、自分のデバッグスキルも格段に上がるはずだ。
次は、この辺りの知識を前提とした「スコープチェーンとクロージャのメモリ管理」の話でもしようか。現場で遭遇する「なぜか値が更新されない」という問題の正体が、そこに見えてくるからね。
それじゃあ、またコードの世界で会おう。健闘を祈る。

コメント