Gyaan

Hoisting

beginner hoisting scope TDZ variables functions

Hoisting is one of those JavaScript behaviors that confuses a lot of beginners. In simple language, hoisting means JavaScript moves declarations to the top of their scope before the code actually runs. But the key detail is — only declarations are hoisted, not initializations.

Think of it like this: before your code runs, JavaScript does a quick scan and says “okay, I see these variables and functions exist” — but it doesn’t assign values yet (for var).

var hoisting

Variables declared with var are hoisted to the top of their function scope and initialized with undefined. This means we can access them before the line where they are declared, but the value will be undefined.

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

What JavaScript actually sees during execution:

var name; // declaration hoisted, initialized with undefined
console.log(name); // undefined
name = "Manish"; // assignment stays in place
console.log(name); // "Manish"

let and const hoisting (Temporal Dead Zone)

let and const are also hoisted — but they are not initialized. They sit in something called the Temporal Dead Zone (TDZ) from the start of the block until the declaration line. Trying to access them in the TDZ throws a ReferenceError.

Block start {
Temporal Dead Zone
accessing x here = ReferenceError
let x = 10; -- TDZ ends here
Safe to use
x is initialized and accessible
}
// console.log(age); // ReferenceError: Cannot access 'age' before initialization
let age = 25;
console.log(age); // 25

The same applies to const. The important thing to remember is — let and const are hoisted (JavaScript knows they exist), but they are not accessible until the declaration line.

Function declaration hoisting

Function declarations are fully hoisted — both the name and the body. This means we can call a function before it appears in the code. This is the one case where hoisting actually feels useful.

greet(); // "Hello!" — works perfectly!

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

Function expressions and arrow functions are NOT hoisted

Function expressions (including arrow functions) behave like variable assignments. The variable is hoisted according to var/let/const rules, but the function body is not. So we cannot call them before the assignment.

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

// sayHi(); // ReferenceError
const sayHi = () => { console.log("Hi!"); };

// hello(); // TypeError / ReferenceError
const hello = function() { console.log("Hello!"); };

If we used var instead of const, we would get a TypeError (because the variable is undefined, and undefined is not a function). With const/let, we get a ReferenceError because of the Temporal Dead Zone.

// sayHi(); // TypeError: sayHi is not a function
var sayHi = () => { console.log("Hi!"); };

// greetFn(); // ReferenceError: Cannot access 'greetFn' before initialization
const greetFn = () => { console.log("Hey!"); };

Quick summary

Declaration
Hoisted?
Initialized?
var
Yes
undefined
let / const
Yes
No (TDZ)
function declaration
Yes
Yes (full body)
function expression / arrow
Like its variable
No

In simple language, only function declarations are fully hoisted and usable before their line. Everything else either gives undefined (var) or throws an error (let/const). When in doubt, just declare things before you use them and you will never have hoisting issues.