Daily Tips & Tricks for Web Enthusiasts

How to Avoid Confusing Code Hoisting Surprises

JavaScript does some things behind the scenes that you may not expect. One of these is called code hoisting, and it can cause some strange issues if you don’t know what’s going on behind the scenes.

The way code hoisting works applies to functions and variables a bit differently, so we’re going to examine each one individually.

Function Hoisting

Let’s start with this example:

function sayHello() {
    console.log('Hello!');
}

sayHello(); // Hello!

That’s pretty straightforward. Running this will log Hello! to the console.

Let’s take a look at another version:

sayHello(); // Hello!

function sayHello() {
    console.log('Hello!');
}

This code works in exactly the same way as the previous example, but how? We called the sayHello() function before we declared it, so why does this code work?

The answer is that the function declaration was hoisted to the top, effectively making both of these examples work as if they were written like the first example.

Whenever you declare and initialize a function with the function keyword, that function is hoisted to the top of the scope where you declared it at runtime. This allows you to call the function before declaring it.

Here’s a longer example that will make this clearer. Examine this code:

piggyOne();

function piggyOne() {
    console.log('Straw!');
}

piggyThree();

function piggyTwo() {
    console.log('Wood!');
}

piggyTwo();

function piggyThree() {
    console.log('Stone!');
}

When this code is run the function declarations will be hoisted, which effectively makes the code run as if it was written like this:

function piggyOne() {
    console.log('Straw!');
}

function piggyTwo() {
    console.log('Wood!');
}

function piggyThree() {
    console.log('Stone!');
}

piggyOne();

piggyThree();

piggyTwo();

That’s essentially how function hoisting works.

Variable Hoisting

Before we dive in to how variables are hoisted it’s important to understand the difference between declaring a variable and initializing a variable.

var theAnswer; // Declaration
theAnswer = 42; // Initialization

Declaring a variable is like saying, “this variable exists,” whereas initialization is like saying, “here’s what this variable contains.”

You can also declare and initialize a variable at the same time:

var theAnswer = 42; // Declaration & Initialization

Now that you know the difference between declaring and initializing a variable, let’s get back to code hoisting by explaining that JavaScript hoists variable declarations, but it does not hoist variable initializations.

Let’s look at some examples, starting with this code, which will throw an error:

console.log(theAnswer); // ReferenceError: theAnswer is not defined

We didn’t define theAnswer, so that error makes sense. Now let’s both define and initialize theAnswer before trying to log it:

var theAnswer = 42;

console.log(theAnswer); // 42

This example logs 42 to the console, as expected.

Now take a look at this:

console.log(theAnswer); // undefined

var theAnswer = 42;

This code logs undefined to the console, which is an interesting outcome.

Remember, JavaScript only hoists variable declarations, not initializations. That means the code above effectively executes like this at runtime:

var theAnswer; // Hoisted!

console.log(theAnswer); // undefined

theAnswer = 42;

The declaration of the variable was hoisted, but the initialization was not. JavaScript is essentially tearing the single line of code that declared and initialized theAnswer in half, and putting the declaration at the top. This prevents the console.log() line from throwing an error, but it because theAnswer hasn’t been initialized yet, the value inside is undefined.

What About Variables Containing Functions?

You might be wondering how code hoisting works in a scenario like this:

sayHello();

var sayHello = function() {
    console.log('Hello!');
}

This code will actually throw an error: TypeError: sayHello is not a function. That’s because, in this case, sayHello is being declared as a variable with the var keyword, so only that variable declaration is hoisted to the top, effectively making the code run like this:

var sayHello; // Hoisted!

sayHello(); // TypeError: sayHello is not a function (execution stops here)

sayHello = function() {
    console.log('Hello!');
}

One thing to note is that JavaScript isn’t actually rewriting your code when it hoists function and variable declarations to the top. What’s going on behind the scenes is a bit complicated, and has to do with JavaScript putting function and variable declarations in memory during the compile phase. The good news is that you don’t need to know the technical specifics of code hoisting to understand how it works and the impact it has on your code.

Now that you know how code hoisting works I recommend you work with it instead of against it. That is, declare your functions and variables first. JavaScript is going to do so anyway, and if your code matches what’s actually going on behind the scenes it will be easier to manage and debug, with fewer surprises.