The Temporal Dead Zone

JavaScript's Restricted Realm for LET and CONST

The Temporal Dead Zone

Photo by John Fowler on Unsplash

The Temporal Dead Zone sounds like a sci-fi movie, doesn't it? But in the JavaScript universe, it's the space where a variable is off-limits, even though you might think it should be available. This behavior occurs with variables declared using let and const.

In this post we will answer the following questions:

  1. What is the Temporal Dead Zone?

  2. Where or when do we encounter it?

  3. Why do we have it?

Before we dive any deeper though, let's review hoisting.

Hoisting: What is it again?!

In The Curious Case of JavaScript Hoisting we talked about how both variable and function declarations are moved - or hoisted - to the top of their containing scope during the compilation phase.

However, not all hoisting is created equal. While function declarations are hoisted with their definitions, allowing us to call them even before their code appears, variables show more nuances:

  • Variables declared with var are hoisted, but their initialization stays where it is. This means they'll exist (with an undefined value) from the beginning of their scope, but they won't get their assigned value until the code execution reaches the point of initialization.

  • In contrast, variables declared with let and const are also hoisted but they enter a 'Temporal Dead Zone'. They remain inaccessible until the point of initialization, and any attempt to access them prematurely will throw an error.

Let's look at an example!

A Variable Declaration with var

console.log(myCat) -> undefined

var myCat = "Petunia"

In the code above, the var myCat declaration is hoisted to the top of the scope, but its initialization with the value "Petunia" is not. This is why it returns undefined when we try to log it before actually defining it.

Now you might ask: what about let and const? Do they also get hoisted? Indeed, they do! JavaScript hoists all declarations, it's very uplifting in that manner. 😊

Yet, while hoisting applies to all three, let and const get special treatment - they get sent to the Temporal Dead Zone! 💀

The Temporal Dead Zone 🚫

The Temporal Dead Zone (TDZ) is JavaScript's no-access zone. When a let or const variable is hoisted, it enters the TDZ. From the start of the block until the line where the variable is declared, it's in the TDZ. Attempt to access it too soon, and JavaScript throws a ReferenceError.

console.log(myVar)   // Output: undefined
var myVar = 'red'    // myVar is now delcared
console.log(myVar)   // Output: 'red'

console.log(myLet)   // ReferenceError: myLet is not defined
let myLet = 'orange' // myLet is now declared
console.log(myLet)   // Output" 'orange'

Notice how myVar floats up like a helium balloon and is undefined before the line where it’s actually tied down. This behavior is because of how var declarations are hoisted. On the other hand, myLet does get hoisted but lounges in the TDZ until the let myLet = "orange" line runs.

Here's an example using const inside a block scope:

{  // start of the block scope

 console.log(cat)      // ReferenceError: cat is not defined
 const cat = "furry"   //  Ah, now cat is finally declared!
 console.log(cat)      // "furry"

}  // End of the block scope

In this example, the scope of cat is the entire block (the code within the { }). The TDZ for cat is the stretch of this block until right before the const cat = "furry" line. Once we pass that line of code, the cat is out of the TDZ ... and out of the bag, ready to be used (and cuddled).

Phew, I am finally in the clear! 😸

Finally: Why Does the TDZ Exist?

Understanding the TDZ is one thing, but you might wonder why such a concept exists in the first place.

The idea behind the TDZ is to help catch bugs in your code. Deciding between var, let, and const for variable declaration? The strict behavior of let and const in TDZ suggests that they are generally better choices for writing robust, debuggable code.

When you declare a variable using var, it gets hoisted and initialized with undefined. Using the variable before it's defined could lead to unexpected behavior, but you will not necessarily see an immediate error. Your code will not explicitly fail; it just operates unexpectedly.

Let's remember an example from a previous post:

var result = 2 * myVar // Output: NaN

var myVar = 7;

In this scenario, result will be NaN because myVar is undefined at the time of the multiplication, and any arithmetic operation involving undefined results in NaN. These types of bugs are subtle and can be tricky to debug as they don’t throw an error and might not become apparent until much later in the program’s execution.

On the other hand, let and const put the variable in the Temporal Dead Zone until it's declared and initialized. If you try to access the variable while it's in the TDZ, JavaScript throws a ReferenceError and the code execution stops; you learn about the potential problem immediately.

Takeaway

Oh, the intricacies of scope, hoisting, and the Temporal Dead Zone! Only in JavaScript, right? It pays to remember them in order to produce bug-resistant code. So, the next time you declare a variable, remember these quirks and choose wisely!

Happy Halloween month! 🎃 😸

Resources

  1. JavaScript: The Definitive Guide

    7th Edition, by David Flanagan

    O'Reilly Media, 2020

  2. Blog post: The Curious Case of JavaScript Hoisting

  3. Blog post: Demystifying Function Declarations Within Conditional Blocks

Blog post originally published on corinamurg.dev.