The mystery of Hoisting in JavaScript

Ali Erbay
5 min readNov 22, 2020

--

In JavaScript, hoisting is a term used to define the movement of function and variable declarations to the top of their scope during the execution of the scope. This happens under the hood so it can become tricky for someone who is unfamiliar with this behavior of JavaScript. One can assume that hoisting involves written code being physically re-arranged but this is not the case. Hoisting is describing the process that occurs while the JavaScript engine interprets written JavaScript code.

Photo by Andrey Kremkov on Unsplash

During this compilation phase, declared variables and functions are stored in memory before the rest of the code is run giving a false sense of the declarations are moved upwards of written code.

Function Declarations and Expressions

For a JavaScript beginner, this might be the first encounter with hoisting. We were all shown that placement of function declarations does not matter while the place of a function expression is important, let’s see that in an example;

printLastName function is hoisted with its declaration and assignment to the top of the code, but only printFirstName’s declaration is hoisted up, it is assignment stays in place in the code. We can visualize the previous code like the following;

As you can see, printLastName’s declaration and assignment are done right away on the top, the function is ready to be called. But in the case of printFirstName, by the time code is read at line 9 printFirstName is undefined therefore it will throw TypeError. We can only run printFirstName properly after its assignment on line 12.

Only Variable Declarations are hoisted ( not variable assignments )

This behaviour is very similar to how function expressions are hoisted. Let’s see it in action;

console.log(x); // undefined
var x = 10;

Some might wrongly think that var x = 10 should be hoisted to the top but this is what actually happens;

var x; // x is hoisted and set to undefined at this point
console.log(x);
x = 10;

It now does seem natural why we are getting x printed as undefined. Variable declaration is hoisted before JavaScript runs the code. The assignment doesn’t happen until later with the code flow. The following code is valid in JavaScript;

x = 5;
console.log(x);
var x;

Different placement of variable declarations inside the same scope will not change anything, you can move var x anywhere you want to since it will be hoisted back to the top anyway.

Let’s check a rare situation where we have the same function name for function declaration and expression

printName();            // output: Morpheus

function printName() {
console.log("Morpheus");
}

var printName = function() {
console.log("Neo");
};

It seems that the function declaration has precedence over the variable declaration. The code above interpreted by JavaScript like the following;

function printName() {   // moved to the top (function declaration)
console.log("Morpheus");
}

var printName; // moved to the top (variable declaration)

printName();

printName = function() { // left in place (variable assignment)
console.log("Neo");
};

Now let’s change the placement of the function call;

var printName = function() {
console.log("Neo");
};

function printName() {
console.log("Morpheus");
}

printName(); // output: Neo

It will be easy to see why it is printed “Neo” if we look at how JavaScripts hoists variable declaration;

function printName(){    // moved to the top (function declaration)
console.log("Morpheus");
}

var printName; // moved to the top (variable declaration)

printName = function(){ // left in place (variable assignment)
console.log("Neo");
};

printName();

Our variable assignment overrides the function declaration variable name here. This gives us two important insights;

  1. Functions declarations are hoisted first before variable declarations( functions expressions also).
  2. It is not a good idea to make duplicate declarations with the same variable name. Duplicate declarations are ignored by the JavaScript engine and can often lead to confusing results. ( this is not the case with the “let” keyword, since the “let” keyword will allow you to re-declare a variable)

ES6 let and const

What about ES6 variables let and const? Are they hoisted too?

Yes, they are but are not assigned with undefined like var, they stay uninitialized. If we use them before they we assign a value to them, they return a ReferenceError rather than undefined.

console.log(x) // Uncaught ReferenceError: x is not defined
let x = 2

These variable declarations only become assigned after compilation and the JavaScript engine starts to evaluate codes line by line. The time between these variables being declared and being evaluated is called the temporal dead zone. Cool name huh! If you try to access variables within this zone, you will get a reference error and if you try to change it before it reaches the declaration line you will get this un-common error message;

x = 2; // ReferenceError: Cannot access 'x' before initialization
console.log(x);
let x;

The previous code will run without any problem if we use “var” instead of “let”.

Some examples that will throw you for a loop

Some of you might think that code above will alert “1” because the if statement should be skipped because bar function scope will get the value of foo from the global scope. But let’s visualize how this code will be interpreted inside of the function bar, it will all make sense;

As you can see, foo is declared inside of bar function as it is hoisted to the top of its scope. At first, foo is undefined so !foo yields true, foo is set to 10 inside of bar function scope, therefore, it should give an alert as “10”.

The second example will be a tad harder to solve if you are a beginner;

You might think that after running, b function variable in the global scope will be updated to 10 since any code after the return statement will be non-effective but it is not true, let’s consider hoisting

As you can see function declaration and its assignment hoisted up and variable a is re-assigned as 10 inside of function b scope. Global scope variable a is not affected therefore code will alert “1”.

Conclusion

Hoisting is one of the concepts of why some people don’t like JavaScript. JS was originally conceived in 1995 as a language to be used by non-expert programmers (i.e. webmasters.) By having function declarations be hoisted, it means that the order is not important, i.e. the call-site for a function can come before the declaration. One of the benefits of hoisting is that it enables us to call functions before they appear in the code, other than that it is just the way how JavaScript interprets your code and every developer should learn how it works in order to write bug-free code.

--

--

Ali Erbay

Full Stack Developer BDD/TDD || Ruby on Rails || React || React Native || NodeJS || Express https://github.com/kermit-klein