Что такое Temporal Dead Zone (TDZ) в JavaScript?
Temporal Dead Zone (TDZ)
Temporal Dead Zone — «временная мёртвая зона» — это концепция, описывающая промежуток времени, в который переменная уже существует в области видимости (благодаря хоистингу), но ещё не инициализирована и недоступна для чтения или записи.
Как это работает
При входе в блок или функцию JavaScript-движок сначала сканирует все объявления переменных. Переменные var поднимаются и сразу инициализируются значением undefined. Переменные let и const тоже поднимаются, но не инициализируются — они находятся в TDZ вплоть до строки с объявлением. Попытка обратиться к ним до этой строки бросает ReferenceError.
console.log(a); // undefined — var поднята и инициализирована
var a = 5;
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;
TDZ в блочной области видимости
TDZ существует именно в блоке, в котором объявлена переменная, а не глобально. Это важно: даже если во внешней области есть переменная с тем же именем, внутри блока она недоступна до объявления.
let x = 'внешняя';
{
// Здесь x попадает в TDZ — внешняя переменная «перекрыта»
console.log(x); // ReferenceError, а не 'внешняя'
let x = 'внутренняя';
console.log(x); // 'внутренняя'
}
TDZ и параметры функции с дефолтными значениями
TDZ также применяется при вычислении дефолтных значений параметров. Параметры вычисляются слева направо, поэтому ссылка на следующий параметр вызовет ошибку.
// Некорректно — b ещё в TDZ при вычислении дефолта для a
function fn(a = b, b = 1) {
return a + b;
}
fn(); // ReferenceError
// Корректно — a уже инициализирована
function fn2(a = 1, b = a) {
return a + b;
}
fn2(); // 2
TDZ и typeof
Одно из важных отличий от var: оператор typeof для переменной в TDZ тоже бросает ReferenceError, тогда как для необъявленной переменной он вернул бы 'undefined'.
console.log(typeof undeclaredVar); // 'undefined' — нет ошибки
console.log(typeof tdzVar); // ReferenceError
let tdzVar = 42;
Зачем TDZ нужна
TDZ — намеренное дизайн-решение для предотвращения ошибок. Использование переменной до её объявления почти всегда является ошибкой. TDZ делает такие ошибки явными и обнаруживаемыми немедленно, а не приводит к скрытому undefined, как это происходит с var.
Практические выводы
- Всегда объявляйте
let/constв начале блока, до первого использования. - TDZ — одна из причин предпочитать
let/constнадvar: поведение более предсказуемо. - В классах TDZ применяется к полям, объявленным через
declareили инициализаторам в теле класса до вызоваsuper()в конструкторе наследника.
Что хочет услышать интервьюер
Кандидат объясняет, что TDZ — это период между хоистингом и инициализацией переменной
Понимает разницу в поведении var (инициализируется undefined) и let/const (остаются в TDZ)
Знает, что обращение к переменной в TDZ вызывает ReferenceError, а не возвращает undefined
Может привести конкретный пример кода с TDZ и объяснить, что произойдёт
Понимает, зачем TDZ введена — для предотвращения скрытых ошибок с использованием переменных до объявления
Пример: TDZ: примеры поведения let/const vs var
// TDZ для let и const
console.log(varVariable); // undefined — var инициализирован сразу
// console.log(letVariable); // ReferenceError: Cannot access 'letVariable' before initialization
var varVariable = 'var';
let letVariable = 'let';
// TDZ в блоке — перекрытие внешней переменной
let value = 'внешняя';
{
// console.log(value); // ReferenceError — внутренний let перекрывает внешний и находится в TDZ
let value = 'внутренняя';
console.log(value); // 'внутренняя'
}
// typeof и TDZ
console.log(typeof notDeclared); // 'undefined' — нет ошибки для необъявленной
// console.log(typeof tdz); // ReferenceError — переменная в TDZ
let tdz = 1;
// TDZ в дефолтных параметрах функции
function bad(a = b, b = 2) { return a + b; } // ReferenceError при вызове
function good(a = 1, b = a) { return a + b; } // 2 — всё корректно
console.log(good()); // 2
Типичные ошибки
Считают, что let/const вообще не хоистятся — на самом деле они хоистятся, но не инициализируются
Путают TDZ с обращением к необъявленной переменной и ожидают undefined вместо ReferenceError
Не знают, что typeof в TDZ бросает ошибку, в отличие от необъявленной переменной
Забывают о TDZ в блочных областях видимости при наличии одноимённой переменной во внешнем скоупе
Не могут объяснить практическую пользу TDZ — воспринимают её как странность, а не защитный механизм


