Understanding Temporal Dead Zone in JavaScript
Temporal Dead Zone is an advanced and interesting topic in JavaScript. To understand what it is and how things work, we need to understand different ways of variable declaration in JavaScript.
Var, Let, and Const
ES6 brought a lot of new features to the language and one of them was the ability to define variables using different keywords which have subtle differences among them (https://www.ecma-international.org/ecma-262/6.0/#sec-let-and-const-declarations).
We can declare variables in three ways
var name = "Yomesh";
let surname = "Gupta";
const profession = "Software Engineer";
Let us understand what are the differences between these three.
Scoping
In the most simple terms, scoping is the area in which a variable is accessible. Scoping of a variable is controlled by the location of its declaration. Let us consider an example.
function init() {
var firstname = "Yomesh";
console.log(firstname); // Yomesh
}
console.log(firstname); // Error
In the above code snippet, variable firstname
is declared inside the function init
i.e. anywhere inside this function we can get or set the value of the variable. However, accessing the same variable outside the function would lead to ReferenceError: firstname is not defined
.
Types of Scoping
We have three types of scoping, namely, Global
, Function
, and Block
scoping. Now you must be thinking what does this all exactly means? Think no more, it is example time!
// Global Scope
var firstname = "Yomesh";function sayName() {
console.log(firstname); // firstname is accessible here
}
function nestedSayName() {
function sayNameNow() {
console.log(firstname); // firstname is accessible here
}
sayNameNow();
}sayName(); // console logs "Yomesh"
nestedSayName(); // console logs "Yomesh"
In the above code snippet, the variable firstname
is declared outside the functions. Any variable which is declared outside of a function will fall into Global scope and is accessible to all parts of the code.
// Function Scope
function sayName() {
var firstname = "Yomesh";
console.log(firstname); // firstname is accessible here
function sayNameNow() {
// firstname is accessible here and we can update it.
firstname = "Ronaldo";
console.log(firstname); // Ronaldo
}
sayNameNow();
}
sayName();
In the above code snippet, variable firstname
is declared inside the function sayName
. It is scoped to that function i.e. it can be used inside the sayName
function or any nested functions. All variables declared via var
are function scoped.
// Block Scope
function sayName() {
var condition = true;
if (condition) {
let firstname = "Cristiano";
const surname = "Ronaldo";
console.log(firstname, surname); // Cristiano Ronaldo
}
console.log(firstname, surname); // ReferenceError
}
In the above code snippet, variables firstname
and surname
are declared inside the scope created by the if
code block. The first console.log
statement logs the value correctly as variables are accessible in that scope. However, the second console.log
throws an error because variables simply don’t exist there.
Declaration & Initialisation
A variable declaration introduces a new identifier. JavaScript interpreter creates a new variable during the creation phase.
var name = "Yomesh"; // allowed
var name = "Cristiano"; // allowed
let surname = "Gupta"; // allowed
let surname = "Ronaldo"; // Error
const profession = "Software Engineer"; // allowed
const profession = "Footballer"; // Error
Any variable declared via var
can be re-declared as many times as we want. However, let
and const
can be only declared once in their respective scope. Variables are declared via var
have the default value of undefined
. Variables declared via let
and const
exist but without a value and cannot be accessed before they are assigned (More on this later).
Binding to the Global Object
var firstname = "Yomesh";
let surname = "Gupta";
const profession = "Software Engineer";// Yomesh Gupta Software Engineer
console.log(firstname, surname, profession);// Yomesh undefined undefined
console.log(window.firstname, window.surname, window.profession);
Variables declared via var
keyword in the global scope are automatically attached to the Global Object i.e. window
in the browsers. The same is not the case with let
and const
.
Understanding Temporal Dead Zone
JavaScript engine runs through our code in two phases — the Creation phase and the Execution Phase. In the first phase, the engine goes through the code and allocates memory for the variables.
console.log(firstname); // undefined
var firstname = "Yomesh";
In the same phase, the variables declared via var
are assigned the value undefined
and that is why in the above code snippet you will get the value of the variable firstname
as undefined
. This is also what we know as “Hoisting”.
console.log(firstname); // ReferenceError
let firstname = "Yomesh";
In the case of the variables declared via let
and const
, they are also allocated memory but they are not assigned the value undefined
initially i.e. variable declarations do hoist but they throw an error till initialized. Let us consider an example.
/*
Since variables are hoisted
it would be equivalent to
let firstname; Beginning of the temporal dead zone*/
console.log(firstname); // ReferenceError as accessed in the TDZfunction init() {
...
}function processing() {
...
}var surname = "Gupta";
var profession = "Software Engineer";
let firstname = "Yomesh"; // Ending of the temporal dead zoneconsole.log(firstname); // Yomesh
As you can see that there exists a region (temporal dead zone) for the variable firstname
which begins from the place where the variable is hoisted as in its scope is created till the place where the variable is initialized. Temporal Dead Zone is a good way to indicate bugs in the code. Accessing variables before declaration is often a root cause of errors.
In the Execution phase, variables are assigned their actual values and it is perfectly fine to use them afterwards.
// Accessing `name` here before execution phase assigns the value to the variable would throw a ReferenceError due to TDZ.
// console.log(name);const name = "Yomesh";console.log(name); // Yomesh | Perfectly fine to use here
Temporal Dead Zone is everywhere. We considered the examples related to variable declarations but it also exists in newer features like Default Parameters
.
I hope this article helped you in some way and gave you more clarity. Let me know your views in the comments or by clicking here. To test your knowledge, try the following question: https://code.devtools.tech/questions/s/what-would-be-the-output-based-on-temporal-dead-zone---qid---aDXxcPUD7LZNdjBCJYo8