Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Temporal dead zone (TDZ)». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**TDZ (temporal dead zone), це проміжок від початку області видимості змінної до моменту її фактичної ініціалізації, протягом якого до змінної не можна звертатися.** У цій «мертвій зоні» змінна вже існує, рушій зареєстрував її під час створення лексичного оточення, але ще не має значення, тож будь-яке звернення кидає `ReferenceError`. TDZ діє для `let`, `const` і `class`: вони теж підіймаються (hoisting), але, на відміну від `var`, не ініціалізуються значенням `undefined`. Навіть `typeof`, який для неоголошеної змінної безпечний, у TDZ кидає помилку. Сенс механізму в передбачуваності: він не дає користуватися змінною до того, як вона справді готова. ```javascript console.log(x); // undefined (var піднято й ініціалізовано) var x = 10; console.log(y); // ReferenceError: Cannot access 'y' before initialization let y = 20; ``` **Ключове:** у TDZ змінна вже існує, але ще не ініціалізована, і звернення до неї, це `ReferenceError`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**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` | | Навіщо потрібна | Запобігає використанню змінних до їхнього оголошення | | Відмінність від `var` | `var` ініціалізується значенням `undefined`, `let`/`const` ні | ### Типові помилки - Казати, що `let` і `const` «не підіймаються». Вони підіймаються, просто не ініціалізуються, і саме тому виникає TDZ. - Покладатися на `typeof` як на безпечну перевірку. Для змінної в TDZ він кидає `ReferenceError`. - Плутати `ReferenceError: Cannot access 'y' before initialization` (TDZ) з `ReferenceError: y is not defined` (змінної немає взагалі). - Використовувати клас вище за його оголошення, розраховуючи на поведінку оголошення функції. Класи мають TDZ. - Забувати, що TDZ прив'язана до **позиції в коді**, а не до часу: виклик функції, який фізично стоїть вище оголошення, але виконується пізніше, спрацює нормально.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.