Hoisting and TDZ in Javascript

Javascript can be tricky to understand sometimes because of how it works. Concepts like Hoisting and TDZ are one of those "Javascript-special" items on the tricky concepts menu. But once we know what it is, it makes all the sense why it is. So, let's get started with our today's topic - Hoisting and TDZ in Javascript.

What is Hoisting?

Hoisting is basically Javascript's default behaviour to move all the variable declarations to the top if its scope.

Which means, you can use the variable before declaring it and it won't throw you any error. See below example:

console.log(myName) // prints "undefined"

var myName = "Omkar"

Someone who comes from a different coding language background will expect this code to throw error. But, above code runs fine without any errors. Seems "wrong", doesn't it? This works because before actually running the code the JS engine moves (hoists) all the declarations at the top - this is called "Hoisting".

While hoisting the variables, the variables defined with var are initialized to undefined by default. Which is why, when we print the myName variable before initializing it with its value "Omkar", it prints "undefined".

This is not the case for variables defined with let and const.

Variables defined with let and const does get hoisted. But, they are not initialized with undefined value by default like var. If you try to use these variables before their declaration, it will throw you a Reference Error saying the variables are not initialized yet. (In case of const, it will throw Syntax Error as seperating out declaration and initialization for const variables is not allowed). See below example:

const printData = () => {
  console.log(varName); //this will print "undefined"
  console.log(letName); // this will throw ReferenceError

  var varName = 'Omkar';
  let letName = 'Jadhav';
};

printData();

This happens because until the varialbles defined with let and const are not declared, they are in Temporal Dead Zone (TDZ)

Temporal Dead Zone (TDZ)

TDZ is for the variables defined with let and const. The TDZ for a variable starts at the beginning of the containing block and ends at its declaration.

Note that the TDZ for that variable ends when it gets declared and not when its initialized.

What's the difference between declaration and initialization ?

See below example:

let name; // 1 --> Declaration

name = "Omkar"; // 2 --> Initialization

let fullName = "Omkar Jadhav"; // 3 --> Declaration & Initialization at same time

As we can see above, we are declaring the variable "name" at line 1. Declaration of a variable reserves some memory for that variable.

At step 2, we are initializing the name variable with value "Omkar".

These two steps can be done at same time like its done for variable fullName at line 3.

const printData = () => {

  // "firstName" is in TDZ
  // "firstName" is in TDZ
  // "firstName" is in TDZ
  // "firstName" is in TDZ
  // "firstName" is in TDZ
  let firstName; // Declaration: TDZ for firstName ends here

  console.log(firstName) // It will print undefined

  firstName = "Omkar" // Initialization

  console.log(firstName) // This will print "Omkar"
};

printData();

In above example, the TDZ for variable "firstName" starts at the start of its block. It stays in TDZ until it gets declared. If it gets used in TDZ, it will throw Reference error.

Once it gets declared, the TDZ for "firstName" ends. It will no longer throw error past this point when it gets used. But, its value would be undefined until it gets initialized with some other value, just like var.

How to avoid getting into TDZ errors?

Simply, we should practice declaring all the required variables at the top of the scope itself. This will make sure you won't get Reference Error.

For more detailed information regarding Temporal Dead Zone, check out this amazing article written by Kealan Parr.

That's all for today. Thanks for reading! Will meet you again with some other blog. Till then, happy coding!