Chapter IX · Scope
Temporal Dead Zone
The Temporal Dead Zone (TDZ) is the span of code — from the start of a scope to the line where a let, const, or class is actually declared — during which that binding exists but cannot be touched.
01 How It Works
Think of a seat with a reservation card on it before the guest has arrived: the seat is accounted for, but sitting in it — even just checking if anyone's there — isn't allowed until the reservation officially starts.
Unlike var, which is hoisted and immediately set to undefined, let and const are hoisted only in the sense that the engine knows the binding will exist somewhere in this scope — but it deliberately leaves it uninitialized until its declaration line actually runs. Any attempt to read or write it before that point throws a ReferenceError, even typeof, which normally never throws for an undeclared name. The TDZ isn't about timing in the real-world sense — it's tied entirely to source-code position within the current scope, from the top of the block down to the declaration.
console.log(count); // ReferenceError: Cannot access 'count' before initialization
let count = 5;
1. A new scope begins; the engine already knows a let/const/class binding exists somewhere in it.
2. Until execution reaches that binding's own declaration line, the name is in its Temporal Dead Zone — any access throws.
3. Once the declaration line runs, the binding is initialized, and it behaves like a normal variable for the rest of the scope.
02 Practical Example
Here is how you might see this concept applied in real-world code:
{
// TDZ for "value" starts here — the block just began
// console.log(value); // would throw ReferenceError
let value = "ready";
console.log(value); // "ready" — TDZ ended the instant the declaration ran
}
// A common misconception: TDZ is not "let is slower to declare" —
// it's a deliberate safety rail. It catches bugs like this early:
function getDiscount(price) {
if (price > 100) {
return price * discountRate; // ReferenceError, not "undefined * price"
}
let discountRate = 0.9;
}
// Without a TDZ, this would silently compute NaN instead of failing loudly.
Key Takeaway
The TDZ isn't a quirk to work around — it's what makes using a let/const before its declaration a loud, immediate error instead of a silent undefined bug.