A Guide to JavaScript Hoisting
- Author: Md. Saad
- Published at: January 12, 2025
- Updated at: January 13, 2025
Introduction
JavaScript hoisting is the process by which the interpreter shifts the declaration of variables, classes, functions, or imports to the top of their scope before executing the code. In this post, we'll learn what hoisting is and how it works.
Understanding of Hoisting
Let’s create an example. Here’s what happens when the following code runs:
console.log(foo);
var foo = 'foo';
In this example, variable foo is assigned a value after the console.log statement. Surprisingly, it does not throw any error. Rather, this code logs undefined instead of throwing an error.
This behaviour occurs because of a JavaScript feature called hoisting. During the execution process, the JavaScript interpreter splits the declaration and assignment of variables and functions. It "hoists" declarations to the top of their scope before executing any code.
In our example, the foo (var foo) declaration is hoisted to the top of the scope, but its assignment (foo = 'foo') remains in place. As a result, when console.log(foo) runs, foo is already declared, but its value is undefined since the assignment hasn't happened yet.
This process is known as hoisting; it allows to use of variables or functions before their declarations in JavaScript.
Variable hoisting in Javascript
In JavaScript, variables can be declared using var, let, or const. For these keywords, hoisting behaves differently.
var Variables:
Variables declared with var are hoisted to the top of their function or global scope. They are initialized with undefined until the code execution reaches their initialization.
Example:
console.log(varHoisting); // Output: undefined
var varHoisting = 5;
console.log(varHoisting); // Output: 5
In the above example, the declaration var x is hoisted, but the initialization varHoisting = 5 is not. Thus, at first, varHoisting value is undefined, but after initialization, the value is 5.
let and const Variables:
Variables declared with let and const are also hoisted, but they are not initialized. Instead, they are placed in a "temporal dead zone" (TDZ) from the start of the block until the declaration is encountered. Accessing these variables before their declaration results in a ReferenceError.
Example:
console.log(letHoisting); // ReferenceError: Cannot access 'y' before initialization
let letHoisting = 10
In the case of let and const, the period between the start of the scope and the actual declaration is called the Temporal Dead Zone.
Function Declarations in Javascript
JavaScript Function declarations are fully hoisted, meaning they can be called before they are declared in the code.
sayHello(); // Output: Hello!
function sayHello() {
console.log('Hello!');
}
In this example, the sayHello() function has been declared before its initialization. This works because the entire function definition is hoisted to the top of the scope.
Function Expressions
Though regular functions are hoisted, function expressions (both regular and arrow functions) don’t hoist. If we try to call the variable that the function expression was assigned to, we will get a TypeError or ReferenceError, depending on the variable's scope. For var it will get TypeError. On the other hand, for let and const it will get ReferenceError
Example:
varFunction(); // Uncaught TypeError: ‘varFunction’ is not a function
var varFunction= function () {
}
letFunction(); // Uncaught ReferenceError: Cannot access 'letFunction’ before initialization
let letFunction= function () {
}
constFunction(); // Uncaught ReferenceError: Cannot access 'consFunction' before initialization
const constFunction = function () {
}
Class Declarations
Classes in JavaScript are hoisted, but similar to let and const, they remain in the temporal dead zone until their declaration is encountered. Accessing a class before its declaration results in a ReferenceError.
Example:
const instance = new MyClass(); // ReferenceError: Cannot access 'MyClass' before initialization
class MyClass {
constructor() {
this.name = 'Example';
}
}
Best Practices to Avoid Issues with Hoisting
- Use let and const Instead of var:
Let and const provide block scope and avoid the unintuitive behaviour of var.
- Declare Variables at the Top of Their Scope:
To improve readability and reduce confusion, always declare variables at the top of the block or function.
- Avoid mixing declarations and initializations:
Keep declarations and initializations close to where they are needed.
- Use Function Expressions for Predictable Behavior:
Prefer using function expressions or arrow functions if you want to avoid hoisting complexities.
Conclusion
Understanding hoisting is critical to developing consistent, bug-free JavaScript code. By knowing how JavaScript moves declarations to the top of their scope and following best practices, one can avoid many common pitfalls associated with hoisting.
Take your understanding of JavaScript to the next level! StaticMania is here to assist you with any challenges or provide feedback. Happy coding!
FAQs
JavaScript hoisting is the process of moving variable, function, and class declarations to the top of their scope before code execution. This allows you to use them before they're actually declared in the code.
No. Variables declared with var are hoisted and initialized to undefined, while let and const are also hoisted but remain in the Temporal Dead Zone until initialization.
If it’s a function declaration, JavaScript hoists the entire definition to call the function beforehand. If it’s a function expression, it won’t work because only the variable declaration is hoisted, not the assignment.
Knowing how hoisting works helps you avoid unexpected behaviors, like undefined variables or errors caused by referencing variables or functions before they’re fully declared.
The TDZ is the period between the start of a block and the point where a let or const variable is declared. Accessing the variable during this period throws a ReferenceError.
Yes. JavaScript classes are hoisted but behave similarly to let and const. Accessing a class before its declaration results in a ReferenceError.
Use let and const instead of var, declare variables and functions at the start of their scope and consider function expressions or arrow functions if you need more predictable behavior.