How JavaScript Works(part 4):

Core Fundamentals(part 4):

Hoisting In JavaScript(Variables and Functions)

var x=1;
function getName(){
console.log("function");
}
getName();
console.log(x);

What do you think the output will be? many of you will guess it right.

output:

function
1

But what if I invoke the function before its initialization? what if I console.log(x) before its initialization? what do you think will happen?

let's see

getName();
console.log(x);

var x=1;
function getName(){
console.log("function");
}

Now guess the output. Many of you will answer it wrong. Let's see what the output is. output:

function
undefined

What is happening here! the function is working still but variable x is giving undefined! why? It is because of Hoisting phenomenon.

All you know or read about hoisting is that "Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution."

But what it actually means let's see step by step.

getName();
console.log(x);

var x=1;
function getName(){
console.log("function");
}

What we are doing in this code is trying to access the function getName() and variable x before declaring/initializing them. In many languages, this will generate an error but in the case of JS, it's quite different.

What we saw was that getName() was somehow able to access the getName function but variable x was not able to access its value, so it gave undefined.

Let's remove x=1 and see what happens.

getName();
console.log(x);

function getName(){
console.log("function");
}

output:

function
Uncaught ReferenceError: x is not defined

Well before it was giving undefined, now it says x is not defined. You will think both undefined and not defined are the same but no, both are not the same thing.

undefined works when we declare a variable in the code but did not assign the value before printing the variable value or use it before its declaration as we have done in this case. not defined works when we did not declare the variable and try to call that variable.

What if we try to console.log function getName as we did with x? Let's see what happens now

//getName();
console.log(getName);

function getName(){
console.log("function");
}

output:

ƒ getName(){
console.log("function");
}

If you see it gave us full function as we were just printing getName. Point to be noted we were not invoking the getName() function rather we were just printing it out and we got full function as output. In the case of variable x, it was giving us undefined but now it is giving us full function. That is a slightly weird thing in JS for beginners to get because they don't know what actually is happening behind the scene.

Let's dive deep into this.

Remember in my 1st and 2nd article we studied execution context, that whenever JS program runs an execution context is created having two phases memory creation phase and code execution phase. Basically, there is the answer.

Note:

If you don't know what execution context is I highly recommend you to read these two articles first.

How JavaScript Works(Part 1):

How JavaScript Works(Part 2)

As you know even before this whole code in JS starts executing the memory is allocated to each and every variable and function. In phase one of the memory creation phase, every variable and function is allocated memory. So x was already allocated memory before code execution and undefined was assigned to it. As in the case of a function, they are assigned the actual copy of the function at the time of the memory creation phase instead of undefined.

This is the main reason function is giving an output of a function or when console.log(getName) it gives full function but x gives undefined.

Till now the way of writing a function we used is known as "Function Declaration." There are two more ways of writing function in JS

  • Function Expression.
  • Arrow Function.

Let's see what happens when we use these two ways.

Arrow function:

getName();
console.log(x);

var x=1;
var getName=()=>{
console.log("function");
}

output:

Uncaught TypeError: getName is not a function
    at <anonymous>:1:1

Function Expression:

getName();
console.log(x);

var x=1;
var getName=function(){
console.log("function");
}

output:

Uncaught TypeError: getName is not a function
    at <anonymous>:1:1

See what happened! Both gave us an error. Can you guess why both are giving us an error? If you can not guess let me clear it for you. In both of these ways instead of acting like a function, getName acts like a variable that receives a function. As variable x was receiving undefined in the memory creation phase so will getName receive in these situations.

So what we got from here is that:

"Arrow Functions & Function expressions in JavaScript are not hoisted, unlike function declarations. You can't use Arrow function & function expressions before you create them"

Hope so you understood what is hoisting and what is the main reason behind it. Now don't just answer "Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution." Tell them clearly what is actually happening behind the scenes.