Scope, hoisting and closures in JavaScript
How var, let and const differ, what hoisting really does, and why closures inside loops behave as they do.
Most JavaScript output questions test one thing: where a variable lives and when it gets its value. Learn the rules for var, let and const, and the classic puzzles become routine.
var, let and const
varis function-scoped. A var declared inside an if block is visible in the whole function.letandconstare block-scoped, so they exist only inside the nearest pair of braces.conststops the variable from being reassigned, but it does not freeze the object it points to.
const user = { name: "Asha" };
user.name = "Ravi"; // allowed
user = {}; // TypeError: Assignment to constant variable.
Hoisting
Before code runs, declarations are registered in their scope. A var is created and set to undefined, so reading it early gives undefined. A let or const is also registered, but it stays in the temporal dead zone until its line runs, and reading it early throws a ReferenceError.
console.log(a); // undefined
var a = 1;
console.log(b); // ReferenceError
let b = 2;
Function declarations are hoisted together with their body, so you can call them before the line where they appear. Function expressions assigned to a variable follow that variable's rules.
Closures
A closure is a function that remembers the variables from the scope where it was created, even after that scope has finished running.
function makeCounter() {
let count = 0;
return function () { count++; return count; };
}
const next = makeCounter();
next(); // 1
next(); // 2
The loop puzzle follows from this. With var i, every callback shares one variable, so timers created in a loop all see its final value. With let i, each iteration gets its own binding, so the callbacks log 0, 1 and 2.
Checklist before answering
- Find the declaration keyword for each variable.
- Decide its scope: function or block.
- Check whether the line reads it before or after its declaration.
- For callbacks, ask which binding they captured.
More in Programming