Hoisting

Why some code works before it appears. Declarations move to the top.

What is Hoisting?

JavaScript moves declarations to the top of their scope before executing.

What you write:

greet();

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

What the engine sees:

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

greet(); // ✓ works!

💡 "Hoisting" isn't literally moving code. The engine scans declarations first (creation phase), then executes. It just appears like declarations moved up.

Function Hoisting

Function declarations are fully hoisted — usable anywhere in their scope.

// ✓ Works — function declarations are hoisted:
const result = add(2, 3); // 5

function add(a, b) {
  return a + b;
}

// ✗ Fails — function expressions are NOT hoisted:
const result2 = multiply(2, 3); // TypeError!

const multiply = function(a, b) {
  return a * b;
};

// ✗ Also fails — arrow functions:
const result3 = divide(10, 2); // TypeError!

const divide = (a, b) => a / b;

✓ Hoisted (fully)

function name() {}

✗ NOT hoisted

const fn = function() {}

const fn = () => {}

var Hoisting

var declarations are hoisted but NOT their assignments.

console.log(x); // undefined (not ReferenceError!)
var x = 5;
console.log(x); // 5

var is hoisted with a value of undefined. The assignment (= 5) stays in place and runs during execution.

💡 Declaration hoisted → value is undefined until assigned
1 / 3

Temporal Dead Zone

let and const exist but can't be accessed until their declaration.

// The Temporal Dead Zone (TDZ):
{
  // ┌── TDZ for 'x' starts ──┐
  // │                          │
  console.log(x); // ReferenceError!
  // │                          │
  // └── TDZ for 'x' ends ─────┘
  let x = 10; // ← x is now initialized
  console.log(x); // 10 ✓
}

// Same for const:
console.log(PI); // ReferenceError!
const PI = 3.14;
console.log(PI); // 3.14 ✓

Timeline of a let/const variable:

TDZ (ReferenceError)
Initialized (safe to use)

↑ declaration reached

Hoisting Precedence

What happens when names collide.

// Function declarations beat var declarations:
var foo = "variable";
function foo() { return "function"; }
console.log(typeof foo); // "function"
// Function was hoisted above the var

// But assignment wins in execution:
var bar = "I win";
function bar() { return "function"; }
console.log(bar); // "I win"
// After execution, the assignment overwrites

// Function declarations beat each other (last wins):
function x() { return 1; }
function x() { return 2; }
x(); // 2 — last declaration wins

💡 Best practice: Use const/let and avoid relying on hoisting. Declare everything before use. Problems with hoisting are why let/const were created.

FAQ

Common questions about hoisting.