Closures
Fundamentals Chapter 5 showed a nested function reading a variable from its enclosing function, and flagged that this "remembering" behaviour is called a closure, promising full coverage later — this is that chapter. A closure is simply a function that keeps access to variables from the scope it was created in, even after that outer scope has technically finished running.
The Basic Closure
makeGreeter finishes running and returns the inner function — but that inner function still remembers whatever greeting was at the moment it was created. sayHello and sayHi are two completely separate closures, each with its own private copy of greeting, even though both were built by the exact same makeGreeter function.
This Is Exactly Fundamentals Chapter 6's makeMultiplier Challenge
That earlier challenge asked why the inner function could still access factor after makeMultiplier had already finished — the answer is exactly this chapter's topic. The returned function "closes over" factor, carrying its own private reference to it for as long as the returned function itself exists.
A Closure Holds a Reference, Not a Snapshot
Each call to the returned function mutates the SAME count variable — it isn't reset, and it isn't a frozen copy taken at creation time. The closure remembers the actual variable, live, the same way two object references (Fundamentals Chapter 7) point at the same underlying object rather than separate copies.
const counterA = makeCounter(); const counterB = makeCounter(); creates two separate count variables — one per call to makeCounter() — so calling counterA() never affects counterB()'s count. Each invocation of the outer function creates a brand-new scope to close over.
The Classic Loop + Closure Pitfall (and Why let Fixes It)
This is the single most famous closure-related bug in JavaScript. With var (Fundamentals Chapter 2's "avoid it" keyword), there's only ever one shared i across the entire loop — by the time any of the three setTimeout callbacks actually runs, the loop has already finished and i is 3. let creates a genuinely new i binding for each iteration, so each callback's closure captures its own separate value.
Practical Use: Private State with a Module-Style Pattern
balance is never a property on the returned object — there is no account.balance to read or overwrite directly. The only way to affect it is through the three methods that closed over it, giving genuine privacy with nothing extra needed: no special keyword, no class syntax (Intermediate Chapter 3) — just an ordinary closure.
addEventListener callback from Fundamentals Chapter 8 is itself a closure — it routinely reaches back to variables declared outside the handler (a counter, a piece of state) and keeps working correctly across repeated clicks, for exactly the same underlying reason as makeCounter above.
Coding Challenges
Write a function makePowerOf(exponent) that returns a function taking a base number and returning base raised to that exponent (use ** for exponentiation). Create square = makePowerOf(2) and cube = makePowerOf(3), then test both with the same input.
📄 View solutionWrite a function makeIdGenerator() that returns a function with no parameters, returning a new sequential ID each time it's called (starting at 1). Create two SEPARATE generators and call each one a few times to prove their counts don't interfere with each other.
📄 View solutionWrite a function createInventory() returning an object with addItem(name, qty), removeItem(name), and getCount(name) methods, all closing over a private object that the caller can never access directly. Add a few items, remove one, and confirm getCount reflects the changes.
📄 View solutionChapter 2 Quick Reference
- Closure — a function that retains access to variables from its creation scope, even after that scope has "finished"
- Each call to the outer function creates a fresh, independent set of variables to close over
- A closure references the real variable, not a frozen snapshot — mutations are visible across calls
- var in a loop + closures = classic bug; let gives each iteration its own binding, fixing it
- Private state pattern: variables declared inside an outer function, exposed only via returned methods
- Event listeners are closures — they routinely reach back to outer variables across repeated events
- Next chapter: ES6 classes — constructors, methods, and inheritance with extends