Hoisting
JavaScript sets up all your declarations before it runs a single line of your code.
Loading visual…
Definition
Before executing a scope, the JavaScript engine scans it and registers every `var` and `function` declaration in advance. Function declarations are hoisted whole, so they can be called before the line where they appear in the source. `var` declarations are hoisted too, but only the declaration, not the assignment, so the variable exists from the top of the scope and reads as `undefined` until its assignment line actually runs. `let` and `const` are also registered ahead of time, but they are not usable until their declaration line executes. The span between the start of the scope and that line is called the temporal dead zone, and touching the variable there throws a `ReferenceError` instead of returning `undefined`. This is why `let`/`const` are described as block-scoped and stricter about ordering, while `var` and function declarations feel like they float upward.
Examples
console.log(a); // undefined
var a = 1;
greet(); // works
function greet() { console.log("hi"); }
console.log(b); // ReferenceError
let b = 2;var is hoisted and initialized to undefined, function declarations are hoisted whole, but let stays in the temporal dead zone until its line runs.
function useHoisted(n) {
return sq(n);
function sq(x) { return x * x; }
}
useHoisted(4); // 16The call to sq happens before its definition in the source, but the hoisted function declaration is already in place when useHoisted starts running.
Where you see this
- Explaining why a var-declared loop counter still exists (as undefined) outside the loop.
- Understanding why calling a function declared lower in a file still works, but a const-assigned function expression does not.
- Debugging a ReferenceError caused by using a let/const variable one line too early.
- Knowing why linters flag var and push teams toward let/const, which fail loudly instead of silently returning undefined.