Hoisting in Javascript


Reading time: 30 minutes | Coding time: 10 minutes

Either you have started learning Javascript or working with it for sometime, you must have came across the term hoisting.

Hoisting is a behaviour in JavaScript in which all variable and function declarations are moved to the top of the code which results in certain code behaviour which we will understand in detail in this article.

Lets look at an example. In this we will create a function and then call it.

function greet(name) {
    console.log('Hey, '+name);
}

greet('Saksham');

As expected when we call our greet function, passing a string 'Saksham'. We will get the message logged on to the console.

Hey, Saksham

But what will happen if we call our function before we actually declare it ?

greet('OpenGenus');

function greet(name) {
    console.log("Hey, "+name);
}

Surprisingly, Hey, OpenGenus is logged to the console.

Hey, OpenGenus

This happens because of Hoisting.

So basically what is happening here ?

Generally, people explain hoisting as variable and function declarations being moved to the top of your code.

While this is what appears to be happening, but this is not in fact what happens. It's important to understand exactly what is going on because one thing for sure code does not move from its position. There is no magic which takes your code to the top of the file.

What actually happens is that our function and variable declarations are added to the memory during the compile phase.

In the above example, because our function declaration was added to the memory during compile time, we're able to access and use it.

Lets look an example for variables.

Usually we declare a variable, initialize it and then attempt to use it.

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

// 10

This gives a normal expected output 10.
But what if we declare our variable at the bottom of our code ?

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

// 10

It still outputs 10. Okay, lets do one more variation.
This time we declare and initialize our variable after the console.log line and lets see what happens.

console.log(a)
var a = 10;

// undefined

Finally, we did it, we broke the expected outcome. We expected 10 but this time we got undefined.

but Why ?
Because Javascript only hoists declarations.

Initializations are not hoisted

If we declare and initialize a variable, say var a = 10;, only the var a; portion (the declaration) is going to be hoisted. The a = 10; (the initialization) is not hoisted and therefore not added to memory.

In one the examples above, when we declare a variable but don't initialize it, the variable is automatically set as undefined . So lets look back at our final example. In the code below, only the var a; will be hoisted:

console.log(a)
var a = 10;

// undefined

Actually, the above code gives same result as writing it like this:

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

// undefined

It still as expected outputs undefined.

ES5

A variable declared with the help of var keyword gets one of the two types of scope:

  • functional scope
  • global scope

Global scoped variables

Lets see how global scoped variables behave-

console.log(a)
var a = 10;

// undefined

This example as we know outputs undefined.
And we know that var a; gets hoisted and behaves likes this-

var a;

console.log(a)
a = 10;

// undefined

Function scoped variables

From what we have understood till now, variables within a global scope are hoisted to the top of the scope. Now let's look at how function scoped variables are hoisted.

function result() {
    console.log(a)
    var a = 10;
}

result();

As you have guessed, the output again is undefined. This is the way it looks for interpreter-

function result() {
    var a;
    console.log(a)
    a = 10;
}

result();

as you can see a is inside a function scope, so it is hoisted inside the function itself instead of very start of the code.

ES6

ES6 also known as ECMAScript 2015 brought some changes to ES5. Two new keywords were introduced for declaring variables - let and const.

let

Variables which are declared with the help of let keyword get block scope instead of function scoped. It means that the scope of a variable is the block in which it is declared and not the function in which it is declared.

Let's start by looking at the let keyword's behavior:

console.log(a);
let a = 10;

Can you guess what will be the output this time?

It gives an error:

// ReferenceError: a is not defined ...

In ES6 we can not use any variable without declaring it and if we try it, it gives an error. This forces us to declare the variable first and then use it.

The following example will output undefined instead of a Reference error.

let a;

console.log(a);
a = 10;

const

In ES6 immutable variables were introduced with the help of const keyword, Immutable variables are variables whose value cannot be modified once assigned.

With const, the variable is hoisted to the top of the block similarly as let does.

Now let's check immutability of variables and see what happens if we try to reassign the value attached to a const variable.

const MAXVAL = 100;

MAXVAL = 200; // Let's reassign the value of MAXVAL

console.log(MAXVAL); 

// Output: TypeError: Assignment to constant variable.

Let's now check how const affects variable declarations.

console.log(a);

const a = 10;

// ReferenceError: hoist is not defined

Again it outputs Reference error similar to let keyword.

The same situation occurs when using const within functions.

Now, what if we declare a const and define after using it ? Lets see -

const a;

console.log(a);
a = 10;

// SyntaxError: Missing initializer in const declaration

This shows that a constant variable must be both declared and initialised before using and only once.

The basic crux of this whole explanation is that:

JavaScript hoists any variable which is declared be it with var,let or const. The difference in this case is how it initialises them. Variables declared with let and const remain uninitialised at the beginning of execution but in case of variables declared with var, they are initialised with a value of undefined.