In this article, we'll look into what hoisting in JavaScript really is.
What is hoisting?
Hoisting is a concept or behavior that exists in languages such as JavaScript, where function and variable declarations are moved to the top of their scope before code execution.
Consider the example below:
function1();
function2();
function function1(){
console.log("I am the first function");
}
function function2(){
console.log("I am the second function");
}
Why does the above code work without any error, especially since the functions have been declared after their execution? Hoisting. We'll dive deeper on the concept and look at how hoisting works in functions, classes and variables.
Hoisting in Functions
In JavaScript, code runs from top to bottom. So in a case such as the function shown below, we would expect to return 3,
since the function is executed just after its declaration.
function sum(a,b) {
return a + b;
}
console.log(sum(1,2)); // return 3
Let's look at another example.
console.log(sum(1,2)); // returns 3
function sum(a,b) {
return a + b;
}
Here we execute the function before declaring it. In hoisting, the function becomes accessible even before its declaration since the function is raised (hoisted) to the top of the scope in which it was defined.
Hoisting, however, would work in functions declared using the function
keyword and not the const
keyword. Hoisting would not work in an arrow function such as the one shown below, and would instead throw a ReferenceError
.
console.log(sum(1,2));
// ReferenceError: Cannot access 'sum' before initialization
const sum = (a,b) => {
return a + b;
}
Hoisting in Variables
In JavaScript, variables can be declared using var
, let
or const
. Hoisting behaves differently based on the variable declaration.
Let's consider the example below:
console.log(num); //returns undefined
var num = 2;
console.log(num); //returns 2
The variable num
is accessed before declaring it. By default, due to hoisting, the variable is hoisted to the top and is initialized with a default value of undefined
. The variable is initialized with its actual value after its declaration.
Hoisting in let
and const
has a different behavior compared to var
. Consider the example below:
console.log(num);
//returns a ReferenceError: Cannot access 'num' before initialization
let num = 2;
Variables declared using let
and const
throw a ReferenceError
since they do not get initialized with a default value of undefined
as is seen in var
declarations. They do get hoisted to the top of the scope but are not accessible, thus the error message explains that it Cannot access 'num' before initialization
. This concept is known as Temporal Dead Zone(TDZ). Let
and const
variables can only be accessed after declaring them.
Hoisting in Classes
Consider the following example:
const Book1 = new Book("Lord of the Rings");
//returns ReferenceError: Cannot access 'Book' before initialization
class Book {
constructor(title) {
this.title = title;
}
}
Just like in let
and const
variables, classes are hoisted to the top of the scope but are inaccessible until they are initialized. The interpreter 'knows' of the existence of the Book
class, but the class cannot be accessed until its initialization.
class Book {
constructor(title) {
this.title = title;
}
}
const Book1 = new Book("Lord of the Rings");
console.log(Book1); //returns Book { title: 'Lord of the Rings' }
The Book
class can only be accessible for instantiation after the class has been initialized.
Wrap Up
JavaScript hoisting involves the process where the interpreter seems to move the declaration of functions and variables to the top of their scope during the compilation phase. This behavior can be quite confusing and can sometimes lead to unexpected results if not properly understood, but with a clear understanding of how hoisting works, developers can leverage hoisting to their advantage and write more organized and maintainable code.