JavaScript | 基礎構文:スコープ・実行コンテキスト - TDZ(Temporal Dead Zone)

JavaScript JavaScript
スポンサーリンク

TDZ(Temporal Dead Zone)って何者?

TDZ は
「変数が“まだ使えない時間帯”のこと
です。

もっと砕くと、

let / const で宣言された変数は、
「スコープに入った瞬間から宣言行までのあいだ」は
そこに“いる”けれど、まだ触るとエラーになるゾーンにいる

この「まだ触っちゃダメな時間帯」が
Temporal(時間的な) Dead Zone(死んでいる領域)=TDZ です。


まずは TDZ が起きる典型的な例

宣言より前で触るとエラーになる

console.log(value); // ここで何が起きる?
let value = 10;
JavaScript

var なら 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
JavaScript

var の場合、
宣言より前でアクセスしてもエラーにはならず、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 に突っ込んだな。宣言より前で使ってないか確認しよう」
と落ち着いてコードの順番を見直してみてください。

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