Temporal Dead Zone (TDZ) Explained
MedThe Temporal Dead Zone (TDZ) is the period between entering a scope and the actual declaration of a let or const variable. During this time, the variable exists but cannot be accessed. Accessing it throws a ReferenceError. The TDZ exists to catch programming errors early - it prevents accessing variables before they are declared, making code more predictable.
Interactive Visualization
Scope Nesting
Variables declared outside any function/block
Key Points
- TDZ = time from scope start to variable declaration
- Variables in TDZ exist but cannot be accessed
- Accessing TDZ variable throws ReferenceError (not undefined)
- typeof behaves differently in TDZ (throws vs returns "undefined")
- TDZ ends at the declaration line, not initialization
- TDZ applies to let, const, and class declarations
Code Examples
Basic TDZ Example
{
// TDZ starts here (beginning of block)
// console.log(value); // ❌ ReferenceError!
let value = 10; // TDZ ends here
console.log(value); // ✅ 10
}From the opening { to the let declaration is the TDZ
typeof in TDZ vs Undeclared
// Undeclared variable console.log(typeof notDeclared); // "undefined" - no error // TDZ variable { // console.log(typeof tdzVar); // ❌ ReferenceError! let tdzVar = 5; } // This difference proves let IS hoisted!
typeof of undeclared returns "undefined" but typeof in TDZ throws. This proves the variable exists (hoisted) but is not accessible.
TDZ in Default Parameters
function example(a = b, b) { // Parameter 'a' default value tries to access 'b' // But 'b' is in TDZ at this point! console.log(a, b); } // example(1, 2); // Works: a=1, b=2 // example(undefined, 2); // ❌ ReferenceError! b is in TDZ // Correct order: function correct(b, a = b) { console.log(a, b); // ✅ Works! } correct(5); // a=5, b=5
Default parameters have their own TDZ - cannot access later parameters
TDZ Across Function Calls
const funcs = []; for (let i = 0; i < 3; i++) { // Each iteration creates a new block scope // New i with its own TDZ funcs.push(function() { console.log(i); }); } funcs[0](); // 0 funcs[1](); // 1 funcs[2](); // 2 // With var, this would print 3, 3, 3!
Each loop iteration creates a new block scope with its own TDZ - why let fixes the classic closure bug
Self-Reference TDZ
// const x = x; // ❌ ReferenceError! x is in its own TDZ // Cannot reference the variable being declared // in its own initialization // Valid with different scope const y = (function() { const y = 10; // This is a different scope! return y; })();
A variable cannot reference itself during initialization - it is in its own TDZ
Common Mistakes
- Thinking TDZ means the variable doesn't exist (it does!)
- Confusing TDZ ReferenceError with "variable not defined"
- Not realizing typeof behaves differently
- Using let/const variables in default parameter expressions of earlier parameters
Interview Tips
- Explain TDZ as "declared but not initialized"
- Use the typeof test to prove the variable exists
- Emphasize TDZ is a ReferenceError, not undefined
- Know that let solves the loop closure problem via TDZ