Dot Net For All

JavaScript Hoisting and Execution context

Hello Friends, In this article I will help you to understand a very confusing and error prone concept known as JavaScript hoisting. If we are not clear about this concept we are exposing ourselves to many potential bugs and errors.

I will explain as well as note down very interesting use cases and examples to make the JavaScript hoisting concept clear.

But before understanding that we should be aware of the Execution context.

JavaScript Execution Context

Whenever we execute a JavaScript file, the JavaScript engine executes the file in two phases. These are:

  1. Creation phase
  2. Execution phase

In the creation phase, even if the JavaScript file is empty, the engine creates two objects. These objects are known as ‘Global’ and ‘this’.

The Global object in case of browsers is known as ‘window’ object. And this is the same as ‘this’ object at global scope.

this and window are equal at global context

Now if we add any variable to the JavaScript, that variable will be added to the ‘window’ object at creation phase.

Variable addition at creation phase.

This is same with the function declaration as well.

In the execution phase the functions are executed one by one. If the JavaScript engine finds an expression with the round brackets like the one below, it knows that if has to execute the function.

bigbrother()

The function encountered first will be kept on the stack, and functions called further inside this function will be kept on the top of the parent function.

Lets see this with the help of an example:

function returnMyName(){
  return 'Vikram Chaudhary';
}

function printMyName(){
  return returnMyName();
}

function callMyName(){
  return printMyName();
}

callMyName();

In the execution phase, JavaScript engine keeps the callMyName() first on the execution stack, than printMyName() and finally returnMyName().

Once a string is returned from returnMyName(), this function is popped out of the stack, than printMyName and finally callMyName.

JavaScript Hoisting and its use cases

Let’s try to guess the result of below three code snippets before talking about hoisting.

console.log("My name is : " + firstName);
var firstName = 'vikram';

and

console.log("My name is : " + firstName);
let firstName = 'vikram';

and

var favouriteCar = 'Tesla';

var myFavouriteCar = function(){
   console.log("My favourite car is: " + favouriteCar);

   var favouriteCar = 'BMW';

   console.log("My new favourite car is: " + favouriteCar);
};

myFavouriteCar();

Lets see the results of the above code examples one by one and try to understand the reason.

My name is : undefined

and

Uncaught ReferenceError: firstName is not defined

finally for the third code snippet.

My favourite car is: undefined
My new favourite car is: BMW

JavaScript engine for all the browsers works in two steps to execute the code. First step is parsing of the JavaScript code file. We call is creation phase. In this phase JS engine quickly goes through the code present in the file and does some normailizations.

The second phase is execution phase where the JS engine executes the code and produces the result.

In the creation phase JS engine performs a special task of hoisting. Using Hosting all the variables and function declarations are declared and initialized at the beginning of the JavaScript code file.

Note that variables are partially hoisted and functions declarations are fully hoisted. It means are variables are initialized with ‘undefined’ and functions along with their definitions are kept the beginning of the JavaScript file.

Now you might be wondering if that is the case, than why the second code snippet is not executing properly. And why it gives a ‘Uncaught reference error’.

The reason is that Hoisting only works for the var and function keywords. It doesn’t work for const or let keywords.

Ideally in other programming languages you cannot use a variable before declaring it in the function scope. And if you are doing so you will get a compiler error. But that is not the case with JavaScript.

Hoisting per Execution context

The third code example is of the hoisting per execution context. Let’s see the code example once more.

In the code example, I have created a function expression named myFavouriteCar. And in the function expression I have used the favouriteCar variable even before declaring it.

But there is already a variable present of the same name at global scope. Ideally the console.log statement should have printed the value present at the global scope.

But that is the not the case. Because the function or method declaration creates its own execution context and declares the undefined variable at the beginning of the function.

That is the reason it prints the ‘undefined’ in the first statement and ‘BMW’ in the second statement.

JavaScript Hoisted function example

As discussed earlier the JavaScript engine only hoists the function and var keywords at the beginning of the execution context.

Let see an example of the hoisted function.

let c = myFunction(1, 2);
console.log(c);

function myFunction(a, b){
   return a + b;
}

In the above code, I am using a function even before declaring it. This has been possible due to function hoisting.

And if I change the above function declaration to function expression as shown below.

let c = myFunction(1, 2);
console.log(c);

var myFunction = function(a, b){
   return a + b;
}

I will get an error as below. The reason for the error is that, since we have a function expression and JavaScript engine declares it as a variable during the creation phase.

Interesting Example of Hoisting

Lets guess the result of the below code example. This is a very nice example of function hoisting and its consequences.

function bigBrother(){
  function littleBrother() {
    return 'it is me!';
  }
  return littleBrother();
  function littleBrother() {
    return 'no me!';
  }
}

bigBrother();

To everyone’s surprise, the result of the above code is ‘no me!’. The reason for the same, is that in the creation phase the JavaScript engine first hoists the function littleBrother with ‘it is me’, but than it sees that there is one more function be with same name.

Now the first function gets overridden by second. And when we finally call this function, we get the result from the second one.

Conclusion:

In this article I have explained in detail about the execution context and JavaScript Hoisting with lots of examples. I hope this will help you to clear the understanding of the concept.

Summary:

  1. JavaScript engine executes the code in two phases i.e. creation phase and execution phase
  2. Variables are partially hoisted. They are initialized with ‘undefined’ value. Functions are fully hoisted.
  3. Variables declared with var keyword are only hoisted not with let, const or any other keywords.

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview