Temporal Dead Zone (TDZ)

TDZ — промежуток между началом блока и точкой инициализации let/const, где переменная объявлена в Environment Record, но доступ к ней даёт ReferenceError.

Что это / Зачем

В отличие от var (который связывается с undefined на фазе создания scope), let/const создаются в специальном состоянии uninitialized (hole). Любое чтение или запись до фактического объявления → ReferenceError: Cannot access 'x' before initialization.

TDZ нужен чтобы:

  • Раннее обнаружение багов — обращение до объявления это почти всегда ошибка
  • Семантика "временной мёртвой зоны" — defenders argue, что переменная не существует, пока не объявлена

Пример

{
  // TDZ для x начинается здесь
  console.log(x); // ReferenceError: Cannot access 'x' before initialization
  console.log(typeof x); // ReferenceError даже для typeof!
  let x = 5;
  // TDZ закончился — x доступна
  console.log(x); // 5
}

Как реализован в V8

На фазе instantiation Environment Record создаётся с binding x в состоянии uninitialized. Каждое использование let/const в TDZ компилируется Ignition в команду ThrowReferenceErrorIfHole — проверка на hole перед чтением.

var такой проверки НЕ имеет — отсюда разница в производительности (см. источники AsForJS).

// Байткод (упрощённо):
// для `let x`:
LdaContextSlot [x]
ThrowReferenceErrorIfHole [x]  // ← проверка TDZ

// для `var x`: ThrowReferenceErrorIfHole отсутствует

Подводные камни

  • typeof x для необъявленной переменной даёт 'undefined' (без ошибки), но typeof x в TDZ даёт ReferenceError — единственное место в JS, где typeof может бросить
  • TDZ работает и для параметров функции: function f(a = b, b) {} → ошибка, потому что b в TDZ
  • class тоже имеет TDZ (как let)
  • const без инициализации — SyntaxError (нельзя оставить hole навсегда)

🎓 Источники

  • ⚡ [Why does everyone use var, let and const incorrectly] · AsForJS · 2021-04-11 · YouTube
    • Тезисы: TDZ заставляет Ignition генерировать ThrowReferenceErrorIfHole на каждое обращение. У var этого нет — это и есть причина "лишнего" кода у let/const
  • ⚡ [⎡spec03⎦ Hoisting согласно спецификации] · AsForJS · 2023-11-19 · YouTube
    • Тезисы: в спеке слова "TDZ" нет, есть uninitialized binding. Любое обращение к uninitialized — ReferenceError по GetBindingValue

См. также