Hoisting and TDZ in Javascript

Hoisting and TDZ in Javascript

ยท

3 min read

What will happen if you execute code bellow?

giveCookie();
function giveCookie() {
  console.log('๐Ÿช');
}
console.log(candy);
var candy = '๐Ÿฌ';
console.log(broccoli);
let broccoli = '๐Ÿฅฆ';

Correct answers are

giveCookie();
function giveCookie() {
  console.log('๐Ÿช');
}
// Output: ๐Ÿช
console.log(candy);
var candy = '๐Ÿฌ';
// Output: undefined
console.log(broccoli);
let broccoli = '๐Ÿฅฆ';
// Output: ReferenceError

The reason behind such results is fairly simple Javascript doesn't like vegies ๐Ÿ˜ž.

Seriously though, it's called hoisting. Hoising is a word that is used to describe the perceived behavior of Javascript when it supposedly moves all declarations to the beginning of the scope. Basically according to this idea code above can be rewritten like so

function giveCookie() {
  console.log('๐Ÿช');
}
giveCookie();
// Output: ๐Ÿช

var candy;
console.log(candy);
candy = '๐Ÿฌ';
// Output: undefined

let broccoli;
console.log(broccoli);
broccoli = '๐Ÿฅฆ';
// Output: undefined

noticed the difference? In an example with let in the first case, it resulted in ReferenceError however after rewriting it in the way how hoisting describes it, it resulted in undefined. Basically hoisting is a lie, Javascript isn't moving declaration to the top. However, it may look like that because the execution of Javascript has two stages. In the first stage, the compiler goes over the code and handles declarations and scopes

giveCookie();
function giveCookie() { // Declare function giveCookie
  // Create new scope
  console.log('๐Ÿช');
}
console.log(candy);
var candy = '๐Ÿฌ'; // Declare variable candy, by default var is undefined
console.log(broccoli);
let broccoli = '๐Ÿฅฆ'; // Declare variable broccoli, by default let & const are not assigned to anything

On the second stage code gets interpreted line-by-line

giveCookie();// Is there declared function giveCookie? YES -> console.log('๐Ÿช');
function giveCookie() {
  console.log('๐Ÿช');
}
console.log(candy); // Is there declared variable candy? YES -> undefined
var candy = '๐Ÿฌ';
console.log(broccoli); // Is there declared variable broccoli? YES -> nothing is assigned to it so ReferenceError!
let broccoli = '๐Ÿฅฆ';

This RefferenceError of let and const is known as TDZ (Temporal Dead Zone). TDZ happens when you are trying to access a variable that isn't fully initialized. When the variable is declared but doesn't have any value assigned to it, because the line that assigns a variable to it wasn't yet been executed. This issue occurs only with let and const because var by default, at the compilation stage, gets assigned undefined, however, let and const get variables only at the interpretation stage.

More examples!

console.log(carrot);
let carrot = '๐Ÿฅ•';
// ReferenceError

function giveIceCream() {
  console.log(iceCream);
}
let iceCream = '๐Ÿจ';
giveIceCream();
// ๐Ÿจ

In the first case, TDZ happens because Javascript still doesn't like vegies ๐Ÿ˜ž, or because you are trying to access a variable before it was fully initialized. In the second case, you fully initialize a variable before executing a function that uses it so you get an ๐Ÿจ.

A bit more tricky example with scope

function sayHi() {
  var name = 'Mark'; // Decleare and assign 'Mark' to name
  if (name) { // name is truth, continue
    let name = `Hi, ${name}` ; // ReferenceError
    console.log(name);
  }
}
sayHi();

This example can be brought down to let name = `Hi, ${name}; in which you are declaring let inside of if statements scope, var name is parent scope so it gets shadowed, and then you are trying to access it immediately before finalizing its declaration.

ย