Javascript’s Temporal Dead Zone (TDZ)

Not to be confused with the “temporal pincer movement” from Christopher Nolan’s 2020 movie Tenet, but perhaps equally confusing, is the concept in Javascript known as the Temporal Dead Zone, or the TDZ.

Neil trying to explain the Temporal Dead Zone

To put it simply, the TDZ is a phase in a variable’s lifecycle where it technically exists, however it cannot be accessed or used – This phenomenon mostly applies to variables defined with the keyword let or const, but not var (And function definitions, too), thanks to the concept of hoisting (More on ‘hoisting’ in a moment – there are a few caveats, which is why I said ‘mostly’).

Let’s take a look at a contrived example to see the TDZ in action:

function myFunction() {
    console.log(x);
    let x = "Hello, world!";
}

myFunction();

The above will result in the following being logged to the JS console:

ReferenceError: Cannot access 'x' before initialization

The JS interpreter knows that x exists, however it cannot access it before it’s been initialized – x is in the temporal dead zone. Think of it this way: You’re going to make a dish that requires bread crumbs. You can see through the clear doors of the cabinet that you have bread crumbs available, but you cannot physically touch them until the doors have been opened. You know they exist, but you just can’t get to them yet. They too are in the temporal dead zone.

Let’s take a look at the same example from above, but using the var keyword to handle the variable declaration:

function myFunction() {
    console.log(x);
    var x = "Hello, world!";
}

myFunction();

The above works… Kind of. Undefined is logged to the console, indicating that x has been initialized, but has yet to be assigned any value. Interesting. Now is a good time to touch on the concept of hoisting.

In JS, hoisting is the concept where all variables (Those declared using var, let, and const) and function declarations get “hoisted” (think: “pulled to the top”) of the current scope. Note how I said declarations – NOT assignments.

Variables defined with var can be accessed before they are initialized, and they can be re-declared in the same scope, whereas variables defined with let and const cannot be accessed before they are initialized (They too are hoisted, but they are in the TDZ), and they cannot be re-declared in the same scope.

This is why in the last example from above where using var resulted in undefined being returned and not a ReferenceError like in the let example. x was declared, however it was not assigned any value, hence it was undefined.

So variables declared with the keyword var can be “used” before they’re actually assigned a value, just expect them to return undefined until they are actually assigned a value, whereas variables defined with let and const will result in a ReferenceError since they live in the temporal dead zone.

So why is the TDZ a thing when it comes to variables defined with either let or const?

Both let and const were introduced in 2015 with ES6, and the concept of the TDZ was born in order to enhance code readability and enforce some level of standardization by encouraging developers to initialize and define variables at the same time. var still exists because backwards compatibility needed to be kept in mind so older code didn’t break. As of 2024, let and const are the preferred key words to use when defining a variable.