A **closure** is formed when an inner function references variables from its outer (enclosing) function. The inner function 'closes over' those variables — they stay alive in memory as long as the inner function exists. Closures enable **private state**, **factory functions**, and the **module pattern**.
1Understanding Closures
A closure is formed when an inner function references variables from its outer (enclosing) function. The inner function 'closes over' those variables — they stay alive in memory as long as the inner function exists. Closures enable private state, factory functions, and the module pattern.
Closures are the basis of most advanced JS patterns: currying, memoization, partial application, and the module pattern.
// Counter with private state
function createCounter(initial = 0) {
let count = initial; // private via closure
return {
increment: () => ++count,
decrement: () => --count,
value: () => count,
reset: () => (count = initial)
};
}
const c = createCounter(10);
console.log(c.increment()); // 11
console.log(c.increment()); // 12
console.log(c.value()); // 122Practical Example
Here is a real-world application of Closures showing how it is used in production JavaScript code.
// Classic closure-in-loop bug
const fns = [];
for (var i = 0; i < 3; i++) {
fns.push(() => i); // all close over same 'i'
}
fns.forEach(f => console.log(f())); // 3 3 3 (bug!)
// Fix: use let
const fns2 = [];
for (let i = 0; i < 3; i++) {
fns2.push(() => i); // each iteration has its own 'i'
}
fns2.forEach(f => console.log(f())); // 0 1 2 (correct!)3Best Practices
Follow these guidelines when working with Closures:
1. Use closures for private state encapsulation
2. Be aware closures prevent GC of outer scope variables
3. Watch for closure-in-loop bugs (use let or IIFE to fix)
Tip: Closures are the basis of most advanced JS patterns: currying, memoization, partial application, and the module pattern.
// Counter with private state
function createCounter(initial = 0) {
let count = initial; // private via closure
return {
increment: () => ++count,
decrement: () => --count,
value: () => count,
reset: () => (count = initial)
};
}
const c = createCounter(10);
console.log(c.increment()); // 11
console.log(c.increment()); // 12
console.log(c.value()); // 12