Temporal Dead Zone (TDZ) Explained

Med

The 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

globalVar

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