Hoisting: More Than "Moving Variables To The Top"

Hoisting is a very popular concept in JavaScript & it is asked in many interviews. Mostly people answer the question "What is hoisting" by saying "Hoisting is when JavaScript moves the variable declarations to the top of the scope", which is correct, if you want to explain to a dummy in layman's terms, but to explain to a person who works with JavaScript or to an interviewer, you might want to know what happens behind the scenes. So let's just dive in.

Note: Before we start, I would highly recommend you to read my article on Execution Context & Call Stack. It is the base of what I am going to explain here. Anyway, I'll be explaining from scratch but I'll be taking a practical approach in this article with examples. If you want to read the theory part please check the previous article.

Hoisting

Let's start with a simple JavaScript program:

function a() {
  console.log("Hello");
}

a(); // Hello

This is a very simple program which prints "Hello" to the console. But let's change this program a little bit.

a();

function a() {
  console.log("Hello");
}

Now, you might think that this is simple, it will result in an error, which is true for any other language, but in JavaScript, that is not the case. It will still print "Hello" to the console. You might be wondering why. If you remember my previous article on Execution Context & Call Stack, I've mentioned that there are 2 phases to the compilation of a JavaScript program - Creation & Execution Phase.

Let's go step-by-step & also console the function a() before it is defined:

  1. In the Creation Phase, the memory to the function a() is allocated & the whole function code is stored in that memory.

  2. In the Execution Phase, when the compiler reaches the 1st line, it checks for the function a() in the memory as it is invoked. Though, the compiler has not yet reached the definition part of the function, the code for the function is already there in the memory & compiler is able to run or print the function. We can put a breakpoint in the line 1 to check this.

You can see that in the Global object we already have an object a which contains all the information regarding the function. Also if you see, the a object also has a Global object nested in it. This is because as explained in the article - Execution Context & Call Stack, every function has it's own Execution Context known as Function Execution Context. Now, if we see the console, we can see the whole function code.

This is called Hoisting. That is why in laymen's terms we say that "Hoisting is when JavaScript moves the variable declarations to the top of the scope". But this is what happens behind the scenes in JavaScript.

JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables or classes to the top of their scope, prior to execution of the code.

Same is the case with variables. If you've declared a variable & you try to print it in the console before assigning a value to that variable, it is undefined. It won't throw any error unlike in other languages, but it'll just print the variable as undefined.

Like in the below image there is breakpoint at line 3 & it will print undefined, because the variable was allocated a memory space during the Creation Phase, but the compiler has not yet reached the line where it is initialized, so the placeholder value of undefined is stored.

And now, if you check the console, you can see, that after the function code, undefined was printed before the initialization. After initialization, the undefined value was updated to "World". To read about undefined in-depth, please check my article on Undefined vs Not Defined vs Null.

Summary

  1. JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables or classes to the top of their scope, prior to execution of the code.

  2. Functions are hoisted by storing the function code in memory. If invoked before the definition, function will still be executed.

  3. Variables are hoisted by storing undefined in the memory. Before initialization variables are undefined.