Lexical Scope & Hoisting
Where names resolve is fixed by where you wrote them -- and what the engine sets up before running a line.
// declarations are registered before execution
function f() {} // hoisted + callable
let x; // hoisted, but TDZ until this lineLexical scope means a variable is resolved by looking at the nesting of the source code, not by who called the function. The scope chain is decided when you write the code, not when it runs.
Hoisting, precisely
Before executing a scope, the engine registers its declarations:
functiondeclarations are fully hoisted -- callable before their line.varis hoisted but initialised toundefined.letandconstare hoisted too, but sit in the temporal dead zone until their declaration runs -- touching them early throws.
console.log(a); // undefined (var hoisted)
var a = 1;
console.log(b); // ReferenceError (TDZ)
let b = 2;The TDZ is a feature: it turns 'used before defined' from a silent undefined into a loud, catchable error.
Example
When to use it
- Call a function declared with function before its definition in the file, relying on hoisting.
- Avoid using a let variable before its declaration to prevent a ReferenceError from the TDZ.
- Understand why a var inside an if block pollutes the enclosing function's scope.
More examples
Function declaration hoisted
Function declarations are fully hoisted, so they can be called before they appear in the source.
console.log(greet("Alice")); // "Hello, Alice" β works before declaration
function greet(name) {
return "Hello, " + name;
}var hoisting vs let TDZ
var hoists the declaration and initialises it to undefined; let is in the temporal dead zone until its line.
console.log(a); // undefined β var is hoisted, not initialised
var a = 10;
// console.log(b); // ReferenceError β TDZ for let
let b = 20;Function expression is NOT hoisted
A function expression assigned to a var is not callable before the assignment, only the var binding is hoisted.
// double(2); // TypeError: double is not a function
var double = function (n) { return n * 2; };
console.log(double(3)); // 6
Discussion