Understanding how Temporal Dead Zone works is quiet confusing, if you we don’t approach properly.
What Exactly Is a Temporal Dead Zone in JavaScript?
A temporal dead zone (TDZ) is the area of a block where a variable is inaccessible until the moment the computer completely initializes it with a value.
- A block is a pair of braces (
{...}
) used to group multiple statements. - Initialization occurs when you assign an initial value to a variable.
Suppose if we attempt to access a variable before , even it is initialized. In such case JavaScript will throw a ReferenceError
.
Before ES6 there was no other way to declare variable other than var
. But as ES6 introduced have two more option to declare variable which is let
and const
.
let
and const
declaration are both block-scoped, which means they are only accessible within the {}
surrounding them. var
, on the other hand doesn’t have this restriction.
Let’s understand with an example.
let myAge = 1;
let isDay = true;
if (isDay) {
let myAge = 2;
}
console.log(myAge); // This prints 1
There are two unique variables, with different values.
It’s happens because the re-declaration of myAge to 2 is only available inside the if block. Beyond that, the first myAge is used. Can you see that they are two different variables?
In contrast, the var
declaration has no block scope
var myAge = 1;
var isDay = true;
if (isDay) {
var myAge = 2;
}
console.log(myAge); // Ah! This prints 2
One variable with its value re-declared. The final salient difference between let/const
and var
is that if you access var
before it’s declared, it is undefined
. But if you do the same for let and const
, they throw a ReferenceError.
console.log(varNumber); // undefined
console.log(letNumber); // Doesn't log, as it throws a ReferenceError letNumber is not defined
var varNumber = 1;
let letNumber = 1;
They throw the error all because of the Temporal Dead Zone.
The let and const
variables exist in the TDZ from the start of their enclosing scope until they are declared.
You could also say that the variables exist in the TDZ from the place they get bound (when the variable gets bound to the scope it’s inside) until it is declared (when a name is reserved in memory for that variable).
{
// This is the temporal dead zone for the age variable!
// This is the temporal dead zone for the age variable!
// This is the temporal dead zone for the age variable!
// This is the temporal dead zone for the age variable!
let age = 25; // Whew, we got there! No more TDZ
console.log(age);
}
You can see above that if I accessed the age variable earlier than its declaration, it would throw a ReferenceError
. Because of the TDZ
.
But var
won’t do that. var
is just default initialized to undefined
unlike the other declaration.
Why is the TDZ created ?
let’s go back to our first example
{
// This is the temporal dead zone for the age variable!
// This is the temporal dead zone for the age variable!
// This is the temporal dead zone for the age variable!
console.log(age);
// This is the temporal dead zone for the age variable!
let age = 25; // Whew, we got there! No more TDZ
}
If we add a console.log inside the TDZ you will see this error
Why does the TDZ exist between the top of the scope and the variable declaration? What’s the specific reason for that?
It’s because of hoisting.
{
// variable will be hoisted to the top of their scope!
console.log(name); // Throws an error, cannot access 'name' before initialization
let name = "Anup Maurya";
}
The above snippet is proof that let is clearly hoisted above where it was declared, as the engine alerts us to the fact. It knows name exists (it’s declared), but we can’t access it before it is initialized.
If it helps you to remember, think of it like this.
When variables get hoisted, var
gets undefined initialized to its value by default in the process of hoisting. let and const
also get hoisted, but don’t get set to undefined
when they get hoisted.
And that’s the sole reason we have the TDZ. Which is why it happens with let and const
but not var.
Why do we have the TDZ?
Dr Alex Rauschmayer has an excellent post on why the TDZ exists, and the main reason is this:
It helps us catch errors.
To try and access a variable before it is declared is the wrong way round, and shouldn’t be possible.
It also gives more expected and rational semantics for const (because const is hoisted, what happens if a programmer tries to use it before it is declared at runtime? What variable should it hold at the point when it gets hoisted?), and was the best approach decided by the ECMAScript spec team.
How to avoid the issues the TDZ causes
Relatively simply, always make sure you define your lets and consts at the top of your scope.