The Temporal Dead Zone
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:
What is the Temporal Dead Zone?
Where or when do we encounter it?
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 anundefined
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
andconst
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
JavaScript: The Definitive Guide
7th Edition, by David Flanagan
O'Reilly Media, 2020
Blog post: The Curious Case of JavaScript Hoisting
Blog post: Demystifying Function Declarations Within Conditional Blocks
Blog post originally published on corinamurg.dev.
Subscribe to my newsletter
Read articles from Corina Murg directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Corina Murg
Corina Murg
I am a self-taught software engineer with a background in math teaching. As a teacher my focus was on creating learning experiences that were inclusive and accessible. For that reason, the frontend's concern with accessible web products deeply resonates with me. I am excited to collaborate on projects with developers from all over the world, and engage in conversations about our responsibility to ensure that every user feels seen and valued. I believe in a web where everyone has a place!