DevPath · Learn to code ESPTEN

Scope, hoisting and closures

Hoisting

Why does something sometimes work "before" you declare it?

Maybe it's happened to you: you call a function on line 2 even though you wrote it on line 20... and it works. It's not magic, it's hoisting.

Hoisting is the behavior by which JavaScript reads your code and, before running it, "moves up" the declarations to the top of their scope. Like tidying the kitchen before you start cooking.

Declared functions: hoisted completely

That's why you can call a function before writing it, with nothing breaking:

greet(); // ✅ works

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

Variables with let and const: the "temporal dead zone"

Variables aren't so friendly. let and const are hoisted too, but JavaScript leaves them "reserved but locked": you can't use them before the line where you declare them. If you try, you get an error:

// console.log(x); // ❌ ReferenceError
let x = 5;

That "forbidden" stretch (from the top of the scope down to its declaration) is called the Temporal Dead Zone. Deep down it's a good thing: it warns you about a mistake instead of carrying on with a weird value.

⚠️ Classic trap: var lies to you with an undefined

With var things go sideways. Using the variable before assigning it does not throw: it returns undefined. And a silent undefined is exactly the kind of bug that takes you an hour to track down. That's another reason to stick with let and const: you'd rather have a clear error than a sneaky undefined.

Examples

We call add before defining it and still get 5: hoisting in action

console.log(add(2, 3)); // 5, even though the definition is below

function add(a, b) {
  return a + b;
}
Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← Scope: global, local and blockClosures →