Manifest Stack home

Hoisting in JS

Part 1: What is Hoisting?

Hoisting is JavaScript's behaviour of moving declarations to the top of their scope during the memory creation phase — before any code actually runs. The code doesn't physically move, but the engine processes declarations first.

Only declarations are hoisted, not initialisations. The name is stored, but the value is not.

Without hoisting, this would fail — but it doesn't

javascript
console.log(name); // undefined (not an error!)
var name = "Arjun";
console.log(name); // Arjun

// What the engine sees (conceptually):
var name;           // declaration hoisted to top
console.log(name);  // undefined (declared but no value yet)
name = "Arjun";     // assignment stays in place
console.log(name);  // Arjun

Part 2: var, let, const — Different Hoisting Behaviour

var — hoisted and initialised as undefined

javascript
console.log(x); // undefined (no error)
var x = 10;
console.log(x); // 10

// var declarations are hoisted AND given the value undefined
// so reading them before assignment gives undefined, not an error

let and const — hoisted but NOT initialised (TDZ)

let and const are hoisted but placed in the Temporal Dead Zone (TDZ). Accessing them before their declaration throws a ReferenceError.

javascript
console.log(y); // ❌ ReferenceError: Cannot access 'y' before initialization
let y = 20;

console.log(z); // ❌ ReferenceError
const z = 30;

// The TDZ is the period between the start of the scope
// and the line where the variable is declared.
// Accessing a variable in its TDZ throws an error.

Side-by-side comparison

var behaviour

javascript
// ✅ No error
console.log(a); // undefined
var a = 1;
console.log(a); // 1

let/const behaviour

javascript
// ❌ ReferenceError
console.log(b);
let b = 1;
console.log(b);

Part 3: Function Hoisting

Function declarations are fully hoisted — the entire function body is stored in memory during the memory phase. This means you can call a function before its definition in the file.

Function declaration — fully hoisted

javascript
greet(); // ✅ Works! Output: Hello!

function greet() {
    console.log("Hello!");
}

// The entire function is hoisted, so calling it before
// the definition is perfectly valid.

Function expression — NOT hoisted (follows variable rules)

javascript
greet(); // ❌ TypeError: greet is not a function

var greet = function() {
    console.log("Hello!");
};

// 'greet' is hoisted as undefined (it's a var)
// calling undefined() → TypeError

// With let:
sayHi(); // ❌ ReferenceError: Cannot access 'sayHi' before initialization
let sayHi = function() { console.log("Hi!"); };

Arrow functions — same as function expressions

javascript
hello(); // ❌ ReferenceError

const hello = () => {
    console.log("Hello!");
};

// Arrow functions assigned to const/let are in the TDZ
// until the line they're declared — same as any let/const