Closures: Functions with Persistent Memories
Quick Overview
A returned function keeps the variables it was created beside, even after the outer call has finished and its frame is gone. That is what makes a private `count` possible with no object at all.
Deep Dive
1. What is a Closure?
A closure is created when an inner function retains access to variables from its outer lexical scope, even AFTER the outer function has finished executing and returned!
2. Why It Matters
Closures power data privacy, private variables, event handlers, factory functions, and stateful hooks in modern JavaScript frameworks like React.
3. The Closure Pattern
When an outer function returns an inner function, the inner function carries a reference to its outer lexical scope in a persistent memory closure:
function createCounter() {
let count = 0; // Private state variable
return function() {
count = count + 1;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
Notice how count remains accessible and remembers its updated state across calls, even though createCounter() finished executing long ago!
4. Visual Closure Memory
[ Execution Context ] -> createCounter() finished & popped off Call Stack
|
v
[ Closure Scope ] -------> count = 3 (Persisted in heap memory!)
^
|
[ Returned Function ] -> counter() reads & updates 'count'
5. Practical Real-World Example: Private State
function createBankAccount(initialBalance) {
let balance = initialBalance; // Fully private variable!
return {
deposit(amount) {
balance += amount;
return balance;
},
getBalance() {
return balance;
},
};
}
const account = createBankAccount(100);
console.log(account.deposit(50)); // 150
console.log(account.balance); // undefined (Cannot access private state directly!)
6. Common Mistakes
- Memory Leaks: Because closures retain references to outer variables, holding large unused objects in closure scopes prevents garbage collection.
- Loop Index Closure Bug: Creating callbacks inside a
varloop captures the final loop value. Useletin loops so each iteration creates a fresh closure environment!
7. Try It Yourself
Write it yourself. The tests below run against your code.
Create Counter Closure Function
Examples
8. Next Steps
Closures give functions durable state memory. Next, let's transition to Phase 3 and master Arrays and Objects!
Next Up in JavaScript Engine & Core Language
Data Types in JavaScript: Primitives vs. Objects
Primitives copy by value and objects copy by reference, so `b = a` duplicates a number but shares an object. That single distinction explains most surprise mutations in a codebase.
Variables: const, let & var (The Box Metaphor)
`const` prevents reassignment, not mutation: a `const` object's properties can still be changed. `let` is scoped to its block, while `var` is function-scoped and leaks out of loops.
Strings & Template Literals `${}`
Only backticks interpolate: `${user}` reads the variable, while the identical text in quotes prints literally. Strings are immutable, so every method returns a new one rather than editing in place.