← Назад к вопросам

Что такое Temporal Dead Zone?

1.6 Junior🔥 131 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Temporal Dead Zone (TDZ)

Temporal Dead Zone — это временной промежуток в JavaScript, при котором переменные, объявленные через let и const, недоступны, хотя переменная уже создана в памяти. Это часто становится причиной непредсказуемых ошибок, если не понимать, как работает hoisting в ES6+.

Как это работает

Когда JavaScript интерпретатор выполняет код, он проходит две фазы:

Фаза 1: Compilation (Parsing)

  • JavaScript сканирует весь код
  • Объявляет все переменные (не инициализирует их)
  • Для var переменные инициализируются с undefined
  • Для let и const переменные остаются в "неинициализированном" состоянии

Фаза 2: Execution (Runtime)

  • Код выполняется строка за строй
  • На момент выполнения переменная может быть либо инициализирована, либо нет
// Пример 1: var (старый способ)
console.log(x); // undefined (hoisting, инициализирована)
var x = 5;
console.log(x); // 5

// Пример 2: let (новый способ, есть TDZ)
console.log(y); // ReferenceError: Cannot access y before initialization
let y = 5;
console.log(y); // 5

// Пример 3: const (новый способ, есть TDZ)
console.log(z); // ReferenceError: Cannot access z before initialization
const z = 5;
console.log(z); // 5

Temporal Dead Zone визуально

// начало области видимости (scope)
// TDZ начинается здесь ↓

console.log(value); // ReferenceError! Мы в TDZ

let value = 10; // TDZ заканчивается здесь ↓

console.log(value); // 10 - теперь переменная инициализирована

Темпоральная мёртвая зона включает всё пространство от начала блока до момента объявления переменной.

TDZ и функции

function example() {
  // TDZ для переменной x начинается здесь
  
  console.log(x); // ReferenceError
  
  let x = 5; // TDZ заканчивается здесь
  
  console.log(x); // 5
}

example();

TDZ и блоки видимости

Kaждый блок (if, for, while, try-catch) создаёт свою область видимости с собственной TDZ:

let x = 1; // глобальная переменная x

if (true) {
  // TDZ для локальной переменной x начинается здесь
  
  console.log(x); // ReferenceError: Cannot access x before initialization
  // Интерпретатор знает, что ниже будет let x, поэтому глобальную x использовать нельзя
  
  let x = 2; // локальная x инициализирована
  
  console.log(x); // 2
}

console.log(x); // 1 (глобальная x)

Это называется shadowing — внутренний блок "скрывает" внешнюю переменную.

TDZ с циклами

// ❌ Проблема: ReferenceError
for (let i = 0; i < 3; i++) {
  console.log(i); // 0, 1, 2 - работает
}

// Это эквивалентно:
for (let i = 0; i < 3; i++) {
  // TDZ для i начинается здесь
  console.log(i); // i уже инициализирована на этом этапе
}

// ❌ ReferenceError в цикле
for (let i = i + 1; i < 5; i++) { // ReferenceError!
  // Здесь i в инициализаторе находится в TDZ
}

TDZ и деструктуризация

// ❌ ReferenceError
const { x = x } = {}; // ReferenceError: Cannot access x before initialization

// Почему? Потому что при деструктуризации переменная x находится в TDZ
// во время вычисления значения по умолчанию

// ✅ Правильно
const { x = 10 } = {}; // x = 10

TDZ и классы

class Animal {}

// ❌ ReferenceError: Cannot access Animal before initialization
const a = new Animal(); // Это не работает

class Animal {}

const a = new Animal(); // ✅ Работает

Классы тоже объявляются с TDZ!

Чем var отличается

// var НЕ имеет TDZ
console.log(oldVariable); // undefined (значение по умолчанию)
var oldVariable = 5;

// let и const ИМЕЮТ TDZ
console.log(newVariable); // ReferenceError
let newVariable = 5;

Этот факт помогает отличить moderne code (ES6+) от старого.

Практический пример: частая ошибка

function checkValue() {
  console.log(typeof x); // ❌ ReferenceError (не undefined!)
  let x = 5;
}

checkValue();

// Это было бы работать с var:
function checkValue() {
  console.log(typeof x); // undefined
  var x = 5;
}

Несколько лет назад разработчики использовали typeof x === undefined для проверки существования переменной. С let и const это больше не работает так как ожидается!

TDZ и условная инициализация

let condition = true;
let value;

if (condition) {
  console.log(value); // undefined - переменная объявлена выше (TDZ нет)
  value = 10;
}

// Но это:
if (condition) {
  console.log(value); // ❌ ReferenceError
  let value = 10;
}

// TDZ для value начинается с открывающей скобки if блока

Почему TDZ существует?

Причина 1: Безопасность

  • Ошибка в коде вызывает исключение, а не молчит
  • var просто возвращает undefined, что может скрыть ошибку

Причина 2: Временная семантика

  • const и let привязаны к временным рамкам блока
  • TDZ обеспечивает, что переменная используется только после инициализации

Причина 3: Предсказуемость

  • Явное лучше неявного
  • Код становится понятнее и безопаснее

Как избежать проблем с TDZ

// ✅ Всегда объявляй переменные в начале блока
function example() {
  let x = 0;  // объявляем в начале
  let y = 0;
  let z = 0;
  
  // затем используем
  x = getValue();
}

// ✅ Не полагайся на hoisting
function example() {
  if (condition) {
    let value = 10;
    console.log(value);
  }
}

// ❌ Избегай
function example() {
  if (condition) {
    console.log(value); // ReferenceError
    let value = 10;
  }
}

Резюме

Temporal Dead Zone — это особенность ES6, которая делает JavaScript безопаснее:

  • Переменные объявлены в памяти, но не инициализированы
  • Попытка доступа вызывает ReferenceError, а не возвращает undefined
  • Это применяется к let, const и классам
  • Помогает избежать ошибок и делает код более предсказуемым