Temporal dead zone (TDZ)
The TDZ (temporal dead zone) is the stretch of time from the start of a variable's scope to the moment it is actually initialised, during which the variable cannot be accessed. Put simply, it is a "dead zone" in which the variable already exists (the engine has registered it) but has not been initialised yet, so trying to use it raises an error.
Theory
TL;DR
- The TDZ is the period between creating a variable's binding and initialising it.
- It applies to
let,constandclass. - Accessing a variable inside its TDZ throws a
ReferenceError. varis hoisted too, but it is initialised toundefinedstraight away, so it has no TDZ.typeofdoes not save you in the TDZ: it throws aReferenceErroras well.- Every block
{ ... }creates its own scope and therefore its own TDZ. - The purpose is safety and predictability: you cannot use a variable before it is declared.
Quick example
console.log(a); // ReferenceError
let a = 10;What happens:
- JavaScript knows
aexists before the code runs, at the point where the lexical environment is created. - But until the line
let a = 10;, the variable sits in the TDZ. - Any attempt to touch it in that zone throws a ReferenceError.
How it differs from var
console.log(x); // undefined
var x = 10;
console.log(y); // ReferenceError
let y = 20;The difference:
varvariables are hoisted and initialised withundefined;letandconstare hoisted as well, but not initialised, and until initialisation they sit in the TDZ.
So hoisting applies to both forms; what differs is whether the binding gets a starting value.
The TDZ inside a block
let a = 1;
{
// the TDZ for b starts here
console.log(a); // 1
// console.log(b); // ReferenceError
let b = 2; // end of the TDZ
console.log(b); // 2
}Every block { ... } creates a new scope, and the let and const variables inside it have their own dead zone up to their initialisation.
The same holds inside a function: the TDZ is in force from the moment you enter its scope until the declaration line.
function foo() {
console.log(bar); // ReferenceError
let bar = "Hello";
}
foo();The TDZ and typeof
The typeof operator is safe for a variable that does not exist at all, but it does not help in the TDZ.
console.log(typeof x); // "undefined"
console.log(typeof y); // ReferenceError
let y = 10;This is one of the very few situations where typeof throws: for a completely undeclared name it returns "undefined", while for a name in the TDZ it raises an error.
The TDZ and class
Classes obey the TDZ too:
const obj = new MyClass(); // ReferenceError
class MyClass {}A class declaration is hoisted, but it sits in the TDZ until its declaration line, exactly like let and const. That is why a class, unlike a function declaration, cannot be used above the place where it is declared.
Why it exists
The TDZ is a safety and predictability mechanism. It stops you using a variable before it is genuinely ready.
If let behaved like var, it would be easy to hit unpredictable bugs caused by undefined that surface far away from their real cause. With the TDZ, the error appears exactly where the problem is.
Visually:
{
// the variable already exists in memory, but is unreachable: this is the TDZ
console.log(x); // ReferenceError
let x = 5; // end of the TDZ, the variable is initialised
console.log(x); // 5
}Summary
| Feature | Description |
|---|---|
| What the TDZ is | The period between creating a variable and initialising it |
| Where it appears | For let, const, class |
| What happens on access | ReferenceError |
| Why it exists | It prevents using variables before their declaration |
Difference from var | var is initialised to undefined, let/const are not |
Common mistakes
- Saying that
letandconst"are not hoisted". They are hoisted, they are just not initialised, and that is precisely what creates the TDZ. - Relying on
typeofas a safe check. For a variable in the TDZ it throws aReferenceError. - Confusing
ReferenceError: Cannot access 'y' before initialization(the TDZ) withReferenceError: y is not defined(no such variable at all). - Using a class above its declaration on the assumption that it behaves like a function declaration. Classes have a TDZ.
- Forgetting that the TDZ is tied to position in the code, not to time: a function call written above the declaration but executed later works fine.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.