TDZ(Temporal Dead Zone)って何者?
TDZ は
「変数が“まだ使えない時間帯”のこと
です。
もっと砕くと、
let/constで宣言された変数は、
「スコープに入った瞬間から宣言行までのあいだ」は
そこに“いる”けれど、まだ触るとエラーになるゾーンにいる
この「まだ触っちゃダメな時間帯」が
Temporal(時間的な) Dead Zone(死んでいる領域)=TDZ です。
まずは TDZ が起きる典型的な例
宣言より前で触るとエラーになる
console.log(value); // ここで何が起きる?
let value = 10;
JavaScriptvar なら undefined が出ますが、let の場合はこうなります。
ReferenceError: Cannot access 'value' before initialization
「初期化される前に value にアクセスできないよ」と怒られます。
ここで重要なのは、
「value が“存在しない”わけではない」ということです。
実はこの時点で、
スコープの中には value という変数枠はもう“用意されている”。
でも、「まだ使ってはいけない状態」 にある。
この「用意はされているけど、まだ触るとエラーになる状態」が
まさに TDZ です。
「スコープに入った瞬間から宣言行まで」が TDZ
コードの流れでイメージしてみる
次のコードを見てください。
{
console.log(num); // ①
let num = 5; // ②
console.log(num); // ③
}
JavaScriptこのブロック { ... } の中で、num の状態は時間とともにこう変わります。
スコープに入った瞬間(ブロックの先頭)
→ num という変数枠は「もうある」
→ でも TDZ 中なので、触るとエラー
① の行(console.log(num);)
→ まだ TDZ 中なので、ReferenceError
② の行(let num = 5;)
→ ここで初めて「初期化」される
→ TDZ を抜ける
③ の行
→ もう TDZ ではないので、5 が表示される
ここが重要です。let / const の変数は「スコープに入った瞬間から存在する」が、
宣言行に到達するまでのあいだは TDZ にいるので、
読み書きしようとするとエラーになる。
var との違いをはっきりさせる
var は TDZ がない(=それが逆に危険)
console.log(a); // undefined
var a = 10;
console.log(a); // 10
JavaScriptvar の場合、
宣言より前でアクセスしてもエラーにはならず、undefined になります。
これは「ホイスティング」と呼ばれる挙動で、var a の宣言だけがスコープの先頭に“持ち上げられたように”扱われるためです。
一方、let / const はこうです。
console.log(b); // ReferenceError
let b = 10;
JavaScriptこの違いが、TDZ の有無です。
var
→ スコープの先頭から「a はある(中身は undefined)」
→ いつでもアクセスできる(ただし値はまだ入ってない)
let / const
→ スコープの先頭から「b の枠はあるが TDZ 中」
→ 宣言行まではアクセス禁止(エラー)
ここが重要です。
TDZ は「宣言前の変数アクセスを“静かに undefined にしない”ための安全装置」。
バグを早期に気づかせるための仕組みです。
TDZ がよく顔を出すパターン
if やブロックの中での宣言
if (true) {
console.log(msg); // ReferenceError
let msg = "こんにちは";
console.log(msg); // こんにちは
}
JavaScriptこの {} の中でも、
スコープの先頭から let msg の行までが TDZ です。
ブロックスコープと TDZ はセットで考えると分かりやすいです。
「ブロックに入った瞬間に変数枠はできる」
「でも宣言行までは TDZ なので触れない」
関数の引数と TDZ(少しだけ)
実は、デフォルト引数の中でも TDZ が関係します。
function greet(name = defaultName) {
const defaultName = "ゲスト";
console.log("こんにちは、" + name + "さん");
}
greet();
JavaScriptこれはエラーになります。
name = defaultName を評価するとき、
まだ defaultName は TDZ の中にいるからです。
ここでは細かい仕様を覚える必要はありません。
「let / const の変数は、宣言より前で使おうとすると TDZ に引っかかる」
という感覚だけ持っておけば十分です。
なぜ TDZ は“良いもの”なのか
「うっかりミス」を早めに爆発させてくれる
もし TDZ がなかったら、
こんなコードも静かに動いてしまいます。
console.log(count); // undefined(本当はバグなのに…)
var count = 10;
doSomething(count);
JavaScript本当は「count を 10 にしてから使うつもり」だったのに、
順番を間違えても undefined のまま進んでしまう。
バグに気づくのはずっと後になります。
let / const + TDZ なら、
同じミスをした瞬間にエラーになります。
console.log(count); // ReferenceError
let count = 10;
doSomething(count);
JavaScriptここが重要です。
TDZ は「厳しい先生」みたいなもの。
“まだ準備できてない変数を使おうとしたら、その場で怒ってくれる”。
だからこそ、バグを早く見つけられる。
初心者として TDZ で本当に押さえてほしいこと
TDZ(Temporal Dead Zone)は、
「let / const の変数が、
スコープに入ってから宣言行に到達するまでの“触っちゃダメな時間帯”」
です。
そのあいだにその変数を読んだり書いたりしようとすると、ReferenceError になる。
これは、
「宣言前に変数を使ってしまう」という
ありがちなミスを、undefined でごまかさずに、
ちゃんとエラーとして教えてくれる仕組み です。
実務的なコツとしては、
宣言はできるだけ上に書く
「あとで使う変数」を前倒しで宣言しておく
宣言前に変数を使っていないか、エディタの警告も活用する
くらいを意識しておけば、
TDZ に悩まされることはほとんどなくなります。
そしてもし ReferenceError: Cannot access 'xxx' before initialization を見たら、
「あ、TDZ に突っ込んだな。宣言より前で使ってないか確認しよう」
と落ち着いてコードの順番を見直してみてください。
