BLOG
ARTICLE

JavaScript Hoisting: A Memo

3 min read

I admit, as a (mainly) backend developer, JavaScript is not a language I explored extensively at work.

But it's good to go back to basic sometimes. So this time I'd like to talk about variable and function hoisting. I'm sure there are better readings out there but I want to make my own memo.

Variable hoisting

JavaScript treats all variables declared anywhere using var as if they are declared on top of the functional scope. To put it simply, it does not matter where the location is, that var will have a value of undefined even before its actual declaration.

This is called hoisting, as in hoisting a flag to the top of the pole it's attached to.

1
2
3
console.log(color); // Expected output: undefined
var color = 'gray';
console.log(color); // Expected output: gray

Another example with function. You can see much clearly here that you will get the color even if you don't pass a parameter to the function.

1
2
3
4
5
6
7
8
9
10
11
getColor() // Expected output: undefined
getColor('blue') // Expected output: gray

function getColor(color) {
    if (color) {
        var color = 'gray';
        console.log(color);
    } else {
        console.log(color);
    }
}

What about let and const?

Well, declaring let is similar to declaring a variable in C-based languages -- you need to declare it first before accessing its value.

1
2
console.log(color); // This will throw error immediately
let color = 'green';
1
2
3
console.log(color); // This will throw error immediately
            ^
ReferenceError: Cannot access 'color' before initialization

That's because let, as opposed to var, has a scope limited to code block only and not subject to hoisting.

Similarly, const will throw an error if accessed before the declaration.

1
2
console.log(color); // This will throw error immediately
const color = 'yellow';
1
2
3
console.log(color); // This will throw error immediately
            ^
ReferenceError: Cannot access 'color' before initialization

The takeaway

Using var without realizing its characteristics will lead to unexpected results.

I personally prefer to use const whenever possible, or if I need to reassign variables, using let to limit the scope would be a good choice.

Function hoisting

Not only var variables can be subjected to hoisting. Functions can too! But it's only when a function is defined through declaration, not expression.

Declaration

You may notice in my above example I called function getColor even before it's declared and it doesn't throw an error. That's because a declared function is hoisted by JavaScript interpreter.

1
2
3
4
5
callBeforeDeclaration();

function callBeforeDeclaration() {
    console.log("This is fine"); // Will be printed
}

Expression

In contrast, any function defined through expression will not be hoisted. Function expression has a similar syntax to function declaration but with one difference: it can be anonymous (not having a function name).

Using an anonymous function before its expression will yield a type error.

1
2
3
4
5
6
console.log(callBeforeExpression); // This is subject to hoisting
callBeforeExpression(); 

var callBeforeExpression = function() {
   console.log("This is not fine");
};
1
2
3
callBeforeExpression();
^
TypeError: callBeforeExpression is not a function

When using function expression, it's advisable to use const instead of var.

More examples of hoisting

Exhibit 1

1
2
3
4
5
6
7
var color = "green";
function getColor() {
    color = "red"; // This will have no effect
    function color() {} // Gets hoisted
}
getColor();
console.log(color);

What's the result? It's green. 🤣 Because function color() got hoisted, assignment color to red inside function getColor() is reduced to the local scope and therefore does not have any effect on the global variable var color.

1
2
3
4
5
6
7
8
// What really happened
var color = "green";
function getColor() {
    function color() {} // Hoisted
    color = "red"; // Reduced to local scope
}
getColor();
console.log(color);

Exhibit 2

1
2
3
4
var color = "red";
console.log(color);
var color = "blue";
console.log(color);

This gives us red and blue respectively. Why? 🤔 Behind the scene, JavaScript hoisted color to the top.

1
2
3
4
// What really happened
var color = undefined
color = "red"
color = "blue"

Exhibit 3

1
2
3
4
5
6
7
8
getColor()
function getColor() {
    console.log("white");
}
getColor();
function getColor() {
    console.log("black");
}

What's the result of console logging? Both are black. 🤣 Setting aside the bizarre fact that we could define 2 functions with the exact names with no error in JavaScript, these functions are subjected to hoisting.

1
2
3
4
5
6
7
8
9
// What really happened
function getColor() {
    console.log("white");
}
function getColor() { // Declared last, became the de facto function
    console.log("black"); 
}
getColor();
getColor();

That's it for now. I will add more examples if I got time. Stay tuned!

Jerfareza Daviano

Hi, I'm Jerfareza
Daviano 👋🏼

Hi, I'm Jerfareza Daviano 👋🏼

I'm a Full Stack Developer from Indonesia currently based in Japan.

Passionate in software development, I write my thoughts and experiments into this personal blog.