Latest Post: Integrating Large Language Models into Frontends

What is Hoisting?

Find out what hoisting is in JavaScript and how it works. Learn how hoisting affects the way you write your code and how you can use it to your advantage.

4 min read
Yello JavaScript color background with the text "Hoisting?"

I am writing this article because I have seen recently a couple of posts on LinkedIn about how junior developers are asked about hoisting in interviews and they don’t know what it is. Even though they might have come across with hoisting, maybe they just do not know the term. So I decided to write this article to explain what hoisting is and how it works. Since I am mainly a frontend dev, I will focus on hoisting in JavaScript.

What is Hoisting in JavaScript and how does it work?

The first thing we have to understand is that we have two phases when we run our JavaScript code: the creation phase and the execution phase. In the creation phase, JavaScript will hoist (elevate, bring to the top) all the variable and function declarations to the top of the scope. This means that JavaScript will read all the variable and function declarations and store them in memory before executing the code.

The term hoistis specially important when comparing behaviours between let, const and var, and also between regular functions and arrow functions. After reading this article, everything will be hopefully crystal clear!

In code, it would look like this:

console.log(myVar) // undefined
var myVar = 'Hello, World!'

In the example above, JavaScript will hoist the variable declaration to the top of the scope, so it will look like this:

var myVar
console.log(myVar) // undefined
myVar = 'Hello, World!'
console.log(myVar) // Hello, World!

So in the first phase, the creation phase, JavaScript will hoist the variable declaration to the top of the scope, but it will not hoist the value assignment. That is why the first console.log will return undefined and the second console.log will return Hello, World!.

However, this does not work like that for let and const variables:

console.log(myVar) // ❌ Uncaught ReferenceError: Cannot access 'myVar' before initialization
let myVar = 'Hello, World!'

As you can see, here we get an error that will break the code!

But how does this work with functions?

Functions actually work in a similar way with the difference that JavaScript will hoist the entire function declaration to the top of the scope, including the value assignment:

sayHello() // ✅ Hello, World!

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

In the example above, JavaScript will hoist the function declaration to the top of the scope, so it will look like this:

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

sayHello() // ✅ Hello, World!

However, this is not true for arrow functions:

sayHello() // ❌ Uncaught ReferenceError: Cannot access 'sayHello' before initialization

const sayHello = () => {
  console.log('Hello, World!')
}

In the example above, JavaScript will hoist the variable declaration to the top of the scope, but it will not hoist the value assignment. That is why the first sayHello() will return Uncaught ReferenceError: Cannot access ‘sayHello’ before initialization. This is called temporal dead zone (TDZ) and it is a characteristic of let and const variables.

const sayHello;
sayHello(); // ❌ Uncaught ReferenceError: Cannot access 'sayHello' before initialization

sayHello = () => {
  console.log('Hello, World!');
};

Why is Hoisting important?

Hoisting is important because it affects the way you write your code. If you are not aware of how hoisting works, you might run into bugs that are hard to debug. For example, if you are using var variables and you are not aware of hoisting, you might run into bugs like this:

var myVar = 'Hello, World!'
console.log(myVar) // Hello, World!

if (true) {
  console.log(myVar) // undefined
  var myVar = 'Hello, Universe!'
  console.log(myVar) // Hello, Universe!
}

To avoid such issues, it’s recommended to use let or const for variable declarations, which have block scope and do not exhibit hoisting in the same way.

In this case, we really want to throw an error if we try to access a variable before it is declared, so we can fix the bug before it happens!

FAQ about Hoisting


Share article