In JavaScript, Hoisting is a behavior of the JavaScript engine that affects how variable and function declarations are interpreted.
Hoisting causes variable and function declarations to be “elevated” to the beginning of their execution context.
By “elevate” the declaration, we mean that the interpreter knows that a function exists, even if we declare it later in the code.
Hoisting is a very useful feature that makes development easier. However, it is also one of the least understood and most confusing concepts.
So let’s take a look at it 👇
What is Hoisting Used For
As I mentioned, Hoisting means that the interpreter knows the variables or functions before their declaration. In other words, we can do this.
greet(); // Output: "Hello, world!"
function greet() {
console.log("Hello, world!");
}
In this case,
- The function
greet
can be called before its declaration - This is because Hoisting “elevates” the declaration.
It may sound a bit strange when read like this, but it makes a lot of sense. The purpose of Hoisting is to simplify our lives when writing code.
If we didn’t have Hoisting, we would have to write functions in the same order we use them.
function function1() {
console.log("Hello, world!");
}
function function2() {
function1();
}
Which may seem like a small problem. But as you write code, you would have to constantly change the order of functions (to be in the same order that you use them).
This would be a real hassle 🙅. So the interpreter first goes through the entire file collecting the definitions to make it easier for us.
JavaScript is not the only language that has this “problem.” Most modern languages do not require maintaining order.
Others do require it, such as C++. So they need other mechanisms like .header files or forward declarations, which are even less intuitive.
How Hoisting Works
Function Hoisting
Functions in JavaScript are fully elevated, both the declaration and the implementation are elevated to the beginning of the execution context.
This means you can invoke them before their declaration. Let’s see an example:
console.log(add(5, 3)); // 8
function add(a, b) {
return a + b;
}
Here, the call to add
is made before the function declaration
Variable Hoisting
Variable declarations using let
and const
are also elevated. However, they are not available before their actual declaration.
This is because the interpreter places them in what we call TDZ (temporal dead zone) until their declaration is reached.
console.log(myLetVariable);
// ReferenceError: Cannot access 'myLetVariable' before initialization
let myLetVariable = 10;
In this case, the code throws a ReferenceError
because myLetVariable
is not defined before its declaration.
It is often said that the definition is elevated, but not the initialization. It doesn’t matter much; the important thing is that the TDZ will not allow you to access it.
Example: Variable Containing a Function
Let’s look at an example that may generate some confusion. What happens if we have a variable that contains a function?
Well, a variable that contains a function is still a variable. So it will follow the rules we have seen regarding variable behavior.
Let’s assume this case,
console.log(multiply(5, 3));
// ReferenceError: Cannot access 'multiply' before initialization
let multiply = function(a, b) {
return a * b;
};
In this case,
- A
ReferenceError
occurs - The error occurs because the variable
multiply
is elevated, but the assignment of the function tomultiply
is not. - Therefore, when trying to call
multiply
before the assignment, an error is thrown because it is in its TDZ - Exactly the same as with a variable containing any other value
Read more
A large part of the confusion caused by Hoisting is due to the use that was previously made of variables declared with var
(which is no longer used)
If you want more information, we can discuss it