What the Hoist 🚩in Javascript ??

What the Hoist 🚩in Javascript ??

Β·

6 min read

Introduction

Before diving deep into the pool of Hoisting, let's get an overview of what it is actually

Hoisting is a mechanism in javascript where the variable and function declarations are moved to the top of their respective scopes before the code execution phase.

Obviously now you must have many doubts after reading the intro. So let's simplify it with an example.

Did you ever notice that you can call a function even before it is declared?

console.log(sayHi())

function sayHi(){
    console.log("Hi Doraemon")
}
// The result of the code is: Hi Doraemon

oh-yes-we-definitely-noticed.jpg

This is where Hoisting comes into play. This is why it happens, the interpreter allocates the memory for the variable and the function declarations before the execution phase.

Let's now see this behaviour in detail with variables and functions.

Hoisting variables

Let's see the sequence by which variable declarations and initialization occurs.

declaration-process.png

var a; // declaration
a = 25; //Initialization / Assignment
console.log(a); // Use in code

var b = 10; // both declare and initialize simulateously

However, even if we simultaneously declare and initialize variables, in the background Javascript is first declaring it and then initializing it.

var

Javascript hoists only the declarations and not initializations of the variables declared using var keyword. If a variable is used in the temporal dead zone (i.e before initialization ), it is default initialized to undefined.

console.log(hoistedVar)
var hoistedVar = "Doraemon"
// The result of the code is undefined

People coming from the background of procedural programming languages like:
C language must have guessed the output as Reference error, but instead, it is undefined.

Wait What?? Magic !! ✨

Actually, Javascript hoisted the variable declaration and default initialized it to undefined. This is how the modified code looks like to the interpreter in the execution phase.

NOTE: It doesn't physically move code

var hoistedVar = undefined;

console.log(hoistedVar); //undefined
hoistedVar = "Doraemon"

Let's take another example to grasp the topic better.

var a = 10;
console.log(a);
var a = 11;
console.log(a);

Can You guess the output?

It's easy, right?

Output:
10
11

But how many times did the variable a got hoisted?
You might have guessed the answer is 2, but it's actually 1 time only. Let's understand why so happens.

In the creation phase, when the Javascript engine sees the variable a, memory will be allocated for that variable and initialized to undefined. When the JS Engine sees the second declaration, it will not care about the value because value is given in the execution phase. Instead, it will check that there is already a variable named a that has been allocated memory, so it will not allocate memory again.

So behind the scene, Javascript sees the code like this:

var a = undefined; // hoisted
a = 10;
console.log(a); // 10
a = 11;
console.log(a); // 11

Variable Hoisting in function scope

Let's see now how variables within function scope are hoisted, by the following example:

function hoistExample(){
    console.log(message);
    var message = "Doraemon";
}

hoistExample();

// The result will be: undefined

If you have guessed the output right, then congratulations to you. If you guessed it wrong I'll explain what's happening here. Behind the scenes, Javascript sees the code like this.

function hoistExample(){
    var message = undefined;
    console.log(message);
    message = "Doraemon";
}

hoistExample()

NOTE: Be careful while working with var because of hoisting. The best practice would be to declare and initialize any variable before use.

let

Variables declared with the let keyword is block-scoped, i.e its lifetime is bound to the block in which it is declared. Let's start seeing the effect of hoisting on let declared variables with an example.

console.log(hoistedLet);
let hoistedLet = "Doraemon";

// The result will be: Uncaught ReferenceError: hoistedLet is not defined

Like before you might have guessed the output as undefined, but in the case of let we cannot use the variables before they are declared.
This ensures that we always declare our variables first.
However be careful, if you declare but do not initialize then you will get the same old result.

let hoistedLet;
console.log(hoistedLet);
hoistedLet = "Doraemon";

// The result will be: undefined

const

Variables declared using const are immutable i.e they cannot be reinitialized. Just like the let, the const variables are hoisted to the top of their own block. Let's see with an example.

console.log(love);
const love = "code";

//The result will be: Uncaught ReferenceError: love is not defined

However in the case of the const variables, if you declare it but do not initialize it before using it, the interpreter will throw an error.

const love;
console.log(love);
love = "code";

//The result will be:
//Uncaught SyntaxError: Missing initializer in const declaration

Therefore a const variable must be both declared and initialized before use.
The conclusion stands that the variables declared with let and const are uninitialized while the variables declared with var is default initialized to undefined before the execution phase.


Hoisting functions

In Javascript functions can be of 2 types:

  1. Function declarations
  2. Function Expressions

Let's see the effect of hoisting on both types of functions.

Function Declarations

Function declarations are hoisted to the top of their scope, that is the reason we can invoke a function even before it is declared.

hoistingFunc();

function hoistingFunc(){
    console.log("Hi Doraemon");
}

//The result will be: Hi Doraemon

In the background what happens is this:

//Declarations moved to the top of scope
function hoistingFunc(){
    console.log("Hi Doraemon");
}

hoistingFunc();

Function Expressions

hoistingExpression()

var hoistingExpression = function(){
    console.log("Hi Doraemon")
}

// The result will be:
// Uncaught TypeError: hoistingExpression is not a function

Let's understand why such an error is thrown. When you use a function expression and assign it to a variable, it now works like a normal variable and not a function. Since it behaves like a variable, all the hoisting properties on variables are applied here.
So in the background, the code looks like this:

var hoistingExpression = undefined;
//Since the variable is initialized to undefined it cannot be invoked
hoistingExpression()

hoistingExpression = function(){
    console.log("Hi Doraemon")
}

If you use ES6 Arrow functions it also behaves the same

hoistingExpression()

var hoistingExpression = ()=> {
    console.log("Hi Doraemon")
}

// The result will be:
// Uncaught TypeError: hoistingExpression is not a function

Similarly, if you declare function declarations using let/const it will behave just like let/const variables.

hoistingExpression()

const hoistingExpression = ()=> {
    console.log("Hi Doraemon")
}

// The result will be:
// Uncaught ReferenceError: hoistingExpression is not defined

Precaution to take to avoid such error πŸ’‰

Strict Mode

Strict Mode is one such utility in Javascript using which we can avoid errors while declaring and initializing variables.
Benefits of running code in strict mode:

  1. Eliminates some JavaScript silent errors by changing them to throw errors.
  2. Fixes mistakes that make it difficult for JavaScript engines to perform optimizations

Enable strict mode in javascript by writing the below code in your file:

"use strict";

Let's test some above code by using 'strict mode'.

"use strict";

console.log(hoistedVar); //ReferenceError: hoistedVar is not defined

hoistedVar = "Doraemon";

That’s all for now, hope you enjoyed reading πŸ˜…

Β