Hoisting is JavaScript’s default behaviour of moving declarations to the top of the current scope (script or function) before code execution. This means that regardless of where functions and variables are declared, they are moved to the top of their containing scope during the compilation phase.
However, it’s essential to note that only declarations are hoisted, not initializations. This distinction plays a critical role in how your code behaves.
1. var Declarations
Variables declared with var are hoisted to the top of their containing scope (function or global) and initialised with undefined. This means you can reference them before their actual declaration without causing a ReferenceError, but their value will be undefined.
Example:
console.log(a); // Output: undefined
var a = 10;
console.log(a); // Output: 10
2. let and const Declarations
Variables declared with let and const are also hoisted to the top of their block scope but are not initialized. They remain in a “temporal dead zone” from the start of the block until their declaration is encountered. Accessing them before declaration results in a ReferenceError.
Example with let:
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
Example with const:
console.log(c); // ReferenceError: Cannot access 'c' before initialization
const c = 30;
3. function Declarations
Function declarations are hoisted to the top of their scope with their entire definition. This allows you to call the function before its declaration in the code.
Examaple:
greet(); // Output: "Hello!"
function greet() {
console.log("Hello!");
}
Explanation:
The entire greet function is hoisted, so calling it before its declaration works seamlessly.
4. Function Expressions
Function expressions behave differently based on how they are declared.
With var:
sayHello(); // TypeError: sayHello is not a function
var sayHello = function() {
console.log("Hi!");
};
Only the variable declaration var sayHello is hoisted and initialized with undefined. The assignment sayHello = function() {…} happens during the execution phase. Therefore, trying to call sayHello before its assignment results in a TypeError because undefined is not a function.
With let or const
sayHi(); // ReferenceError: Cannot access 'sayHi' before initialization
let sayHi = function() {
console.log("Hi there!");
};
Similar to variable hoisting with let and const, the function expression is in the temporal dead zone, and accessing it before declaration throws a ReferenceError.
What is Temporal Dead Zone?
The Temporal Dead Zone (TDZ) refers to the period in a JavaScript program where variables declared with let and const are hoisted but not yet initialized. During this time, accessing these variables results in a ReferenceError. The TDZ exists from the start of the block until the variable declaration is processed.
In simpler terms, while var declarations are hoisted and initialized with undefined, let and const declarations are hoisted without initialization, leading to the TDZ where the variables cannot be accessed.
For detailed explanation: