Skip to main content

Temporal dead zone (TDZ)

TDZ (temporal dead zone), це проміжок часу від початку області видимості змінної до моменту її фактичної ініціалізації, коли до неї не можна звертатися. Простіше кажучи, це «мертва зона», у якій змінна вже існує (зареєстрована рушієм), але ще не ініціалізована, і спроба її використати призводить до помилки.

Теорія

TL;DR

  • TDZ, це період між створенням зв'язування для змінної та її ініціалізацією.
  • Діє для let, const і class.
  • Звернення до змінної в TDZ кидає ReferenceError.
  • var теж підіймається, але одразу ініціалізується значенням undefined, тому TDZ не має.
  • typeof у TDZ не рятує: він теж кидає ReferenceError.
  • Кожен блок { ... } створює власну область видимості, а отже і власну TDZ.
  • Призначення механізму, безпека й передбачуваність: не дати скористатися змінною до її оголошення.

Швидкий приклад

javascript
console.log(a); // ReferenceError let a = 10;

Що відбувається:

  1. JavaScript знає про існування a ще до виконання коду, на етапі створення лексичного оточення.
  2. Але до рядка let a = 10; змінна перебуває в TDZ.
  3. Будь-яка спроба звернутися до неї в цій зоні кидає ReferenceError.

Відмінність від var

javascript
console.log(x); // undefined var x = 10; console.log(y); // ReferenceError let y = 20;

Різниця:

  • змінні var підіймаються (hoisting) і ініціалізуються значенням undefined;
  • let і const теж підіймаються, але не ініціалізуються, і до моменту ініціалізації перебувають у TDZ.

Тобто hoisting стосується обох форм; відрізняється лише те, чи отримує зв'язування початкове значення.

TDZ усередині блока

javascript
let a = 1; { // TDZ для b починається тут console.log(a); // 1 // console.log(b); // ReferenceError let b = 2; // кінець TDZ console.log(b); // 2 }

Кожен блок { ... } створює нову область видимості, і змінні let та const усередині нього мають власну «мертву зону» до своєї ініціалізації.

Те саме працює й у функції: TDZ діє з моменту входу в її область видимості й до рядка оголошення.

javascript
function foo() { console.log(bar); // ReferenceError let bar = "Hello"; } foo();

TDZ і typeof

Оператор typeof безпечний для змінної, якої взагалі не існує, але в TDZ він не рятує.

javascript
console.log(typeof x); // "undefined" console.log(typeof y); // ReferenceError let y = 10;

Це одна з небагатьох ситуацій, коли typeof кидає виняток: для повністю неоголошеного імені він повертає "undefined", а для імені в TDZ, помилку.

TDZ і class

Класи теж підпорядковуються TDZ:

javascript
const obj = new MyClass(); // ReferenceError class MyClass {}

Оголошення класу підіймається, але перебуває в TDZ до рядка оголошення, точнісінько як let і const. Саме тому клас, на відміну від оголошення функції, не можна використати вище за місцем оголошення.

Навіщо це потрібно

TDZ, це механізм безпеки та передбачуваності. Він не дає використати змінну до того, як вона справді готова.

Якби let поводився як var, ми б легко ловили непередбачувані помилки через undefined, які виявляються далеко від місця справжньої причини. З TDZ помилка виникає рівно там, де є проблема.

Візуально:

javascript
{ // змінна вже існує в пам'яті, але недоступна: це TDZ console.log(x); // ReferenceError let x = 5; // кінець TDZ, змінна ініціалізована console.log(x); // 5 }

Підсумок

ОсобливістьОпис
Що таке TDZПеріод між створенням змінної та її ініціалізацією
Де виникаєДля let, const, class
Що стається при зверненніReferenceError
Навіщо потрібнаЗапобігає використанню змінних до їхнього оголошення
Відмінність від varvar ініціалізується значенням undefined, let/const ні

Типові помилки

  • Казати, що let і const «не підіймаються». Вони підіймаються, просто не ініціалізуються, і саме тому виникає TDZ.
  • Покладатися на typeof як на безпечну перевірку. Для змінної в TDZ він кидає ReferenceError.
  • Плутати ReferenceError: Cannot access 'y' before initialization (TDZ) з ReferenceError: y is not defined (змінної немає взагалі).
  • Використовувати клас вище за його оголошення, розраховуючи на поведінку оголошення функції. Класи мають TDZ.
  • Забувати, що TDZ прив'язана до позиції в коді, а не до часу: виклик функції, який фізично стоїть вище оголошення, але виконується пізніше, спрацює нормально.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.