【実務・中級編】 letとconstの巻き上げと一時的死域(TDZ) – JavaScript実践ガイド

「巻き上げ」の裏側を知れば、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は怖くない。むしろ、あなたのコードが正しく動くことを保証してくれる「番人」だと思ってほしい。この挙動を理解しているだけで、コードレビューの質も、自分のデバッグスキルも格段に上がるはずだ。

次は、この辺りの知識を前提とした「スコープチェーンとクロージャのメモリ管理」の話でもしようか。現場で遭遇する「なぜか値が更新されない」という問題の正体が、そこに見えてくるからね。

それじゃあ、またコードの世界で会おう。健闘を祈る。

コメント

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