Closures
Closures
Section titled βClosuresβWhat it means
Section titled βWhat it meansβA closure is a function that βremembersβ the variables from the scope it was created in, even after that outer scope has finished executing. This is possible because of JavaScriptβs lexical scoping β a functionβs access to variables is determined by where itβs defined, not where itβs called.
Examples
Section titled βExamplesβfunction makeCounter() { let count = 0; // this variable is "closed over" return function () { count += 1; return count; };}
const counter = makeCounter();console.log(counter()); // 1console.log(counter()); // 2console.log(counter()); // 3 -- `count` persisted between calls
function makeMultiplier(factor) { return (n) => n * factor; // remembers `factor` from the outer scope}
const double = makeMultiplier(2);console.log(double(5)); // 10Common mistake
Section titled βCommon mistakeβCreating closures inside a loop using var β since var is function-scoped (not block-scoped), every closure ends up sharing the same variable, which holds its final value by the time the closures run.
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0);}// prints 3, 3, 3 -- all closures share the same `i`
for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0);}// prints 0, 1, 2 -- `let` creates a new binding per iterationQuick practice
Section titled βQuick practiceβ-
Why does
makeCounter()remembercountbetween calls?Answer
The inner function forms a closure overcountβ it keeps a live reference to that variable in its enclosing scope, which persists as long as the closure exists. -
Why does using
varin a loop withsetTimeoutprint the same value every time?Answer
varis function-scoped, so all iterations share one variable; by the time the timeouts fire, the loop has finished and the variable holds its final value. -
What fixes the loop-closure bug from question 2?
Answer
Usingletinstead ofvarβletcreates a fresh, block-scoped binding for each iteration.