How Does Hoisting Work in JavaScript?
Answer
Hoisting is JavaScript's behavior of moving declarations to the top of their scope during the compilation phase, before code execution.
Hoisting Visualization
var Hoisting
// What you write
console.log(name); // undefined (not error!)
var name = "John";
console.log(name); // "John"
// How JavaScript interprets it
var name; // Declaration hoisted
console.log(name); // undefined
name = "John"; // Assignment stays in place
console.log(name); // "John"
let and const Hoisting
// let and const are hoisted BUT not initialized
// They exist in "Temporal Dead Zone" (TDZ)
console.log(name); // ReferenceError: Cannot access before initialization
let name = "John";
console.log(age); // ReferenceError: Cannot access before initialization
const age = 25;
Temporal Dead Zone (TDZ)
{
// TDZ starts here for 'x'
console.log(x); // ReferenceError
let x = 10; // TDZ ends
console.log(x); // 10
}
Function Hoisting
// Function declarations are fully hoisted
sayHello(); // "Hello!" (works!)
function sayHello() {
console.log("Hello!");
}
// Function expressions are NOT hoisted
sayGoodbye(); // TypeError: sayGoodbye is not a function
var sayGoodbye = function () {
console.log("Goodbye!");
};
Arrow Functions
// Arrow functions behave like function expressions
greet(); // TypeError: greet is not a function
var greet = () => {
console.log("Hi!");
};
// With let/const - even worse (TDZ)
welcome(); // ReferenceError: Cannot access before initialization
const welcome = () => {
console.log("Welcome!");
};
Class Hoisting
// Classes are hoisted but remain in TDZ
const p = new Person(); // ReferenceError
class Person {
constructor(name) {
this.name = name;
}
}
Hoisting Priority
// Function declarations take precedence over var
console.log(typeof foo); // "function"
var foo = "variable";
function foo() {
return "function";
}
console.log(typeof foo); // "string" (var assignment happened last)
Practical Example
// Why this causes confusion
var count = 10;
function example() {
console.log(count); // undefined (not 10!)
var count = 20;
console.log(count); // 20
}
example();
// Because JavaScript sees it as:
function example() {
var count; // Hoisted declaration
console.log(count); // undefined
count = 20;
console.log(count); // 20
}
Best Practices
// ✅ Good: Declare at the top
function example() {
let count = 0;
const MAX = 100;
// Use variables here
}
// ✅ Good: Use let/const to catch TDZ errors
// ❌ Avoid: Relying on var hoisting
// ✅ Good: Declare functions before calling
function greet() {
console.log("Hi");
}
greet();
// ❌ Avoid: Calling functions before declaration
Summary Table
| Declaration | Hoisted? | Initialized? | Can Use Before? |
|---|---|---|---|
var | ✅ Yes | undefined | ⚠️ undefined |
let | ✅ Yes | ❌ No (TDZ) | ❌ ReferenceError |
const | ✅ Yes | ❌ No (TDZ) | ❌ ReferenceError |
function | ✅ Yes | ✅ Yes | ✅ Yes |
class | ✅ Yes | ❌ No (TDZ) | ❌ ReferenceError |
Key Points
- All declarations are hoisted to scope top
varis initialized withundefinedlet/constare in TDZ until initialization- Function declarations are fully hoisted
- Function expressions follow
var/let/construles - Best practice: Declare before use, prefer
let/const