Master how closures capture variables so you can encapsulate state and avoid scoping pitfalls.
Open this lesson in KodokonA closure is not some exotic trick: it is the mechanism by which a function keeps access to the lexical scope where it was defined, not the one where it is called. The engine does not copy values: it keeps a live reference to the lexical environment. Two calls to the same factory therefore produce two independent environments, which makes closures the most lightweight encapsulation tool in the language.
function createCounter() {
let count = 0;
return {
increment: () => ++count,
reset: () => { count = 0; },
};
}
const counterA = createCounter();
const counterB = createCounter();
counterA.increment();
counterA.increment();
console.log(counterA.increment()); // 3
console.log(counterB.increment()); // 1The classic real-world trap: var is bound to the enclosing function, not to the block. Inside a loop, every closure then captures the same variable. With let, each iteration creates a fresh lexical environment, so each capture is distinct. Add to that the temporal dead zone (TDZ): a let or const variable exists as soon as the block is entered but throws a ReferenceError if you read it before its declaration.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 3, 3, 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0); // 0, 1, 2
}Pattern-wise, closures are the foundation of memoization and the module pattern. Compared to a class, a closure gives you genuine privacy without this or prototypes, at the cost of slightly higher memory usage when you create thousands of instances: each instance carries its own functions.
function memoize(fn) {
const cache = new Map();
return function (key) {
if (cache.has(key)) return cache.get(key);
const result = fn(key);
cache.set(key, result);
return result;
};
}
const square = (n) => n * n;
const fastSquare = memoize(square);
console.log(fastSquare(9)); // computed
console.log(fastSquare(9)); // read from the cachefor (var i = ...) loop, what do three setTimeout callbacks created inside the loop body log?createCounter guarantee that count stays private?