Practical Closure Patterns
MedClosures enable powerful patterns in JavaScript: data privacy (making variables private), function factories (creating functions with preset values), maintaining state in callbacks, and memoization (caching expensive computations). These patterns are used extensively in real-world code and frameworks.
Interactive Visualization
CodeCreation Phase
1function outer() {2 let x = 10;3 function inner() {4 return x;5 }6 return inner;7}89const fn = outer();10fn(); // 10
Call Stack
Global EC
Variables:
fnundefined
Heap Memory
(empty)
Output
—
Global EC created - outer function is defined
1 / 6
Key Insight: A closure is formed when an inner function is returned from an outer function, maintaining access to the outer function's variables even after the outer function has completed.
Key Points
- Data privacy: closures hide variables from external access
- Function factories: create specialized functions with preset configuration
- State preservation: maintain state in event handlers and callbacks
- Memoization: cache expensive function results
- Module pattern: use IIFE + closure for encapsulation
Code Examples
Data Privacy (Private Variables)
function createBankAccount(initialBalance) { let balance = initialBalance; // Private variable! return { deposit(amount) { if (amount > 0) { balance += amount; return balance; } return "Invalid amount"; }, withdraw(amount) { if (amount > 0 && amount <= balance) { balance -= amount; return balance; } return "Insufficient funds"; }, getBalance() { return balance; } }; } const account = createBankAccount(100); console.log(account.getBalance()); // 100 console.log(account.balance); // undefined - private! account.deposit(50); console.log(account.getBalance()); // 150
The balance variable is hidden from external access - only methods in the closure can access it.
Function Factory
function makeMultiplier(factor) { // factor is captured in closure return function(number) { return number * factor; }; } const double = makeMultiplier(2); const triple = makeMultiplier(3); const halve = makeMultiplier(0.5); console.log(double(5)); // 10 console.log(triple(5)); // 15 console.log(halve(10)); // 5 // Each function has its own factor in closure
Function factories create specialized functions with preset values captured in closure.
Once Function (Run Only Once)
function once(fn) { let ran = false; let result; return function(...args) { if (!ran) { ran = true; result = fn.apply(this, args); } return result; }; } const initialize = once(() => { console.log("Initializing..."); return "Setup complete"; }); console.log(initialize()); // "Initializing...", "Setup complete" console.log(initialize()); // "Setup complete" (no log) console.log(initialize()); // "Setup complete" (no log) // The ran variable is preserved in closure
Closures can track state - in this case, whether a function has been called.
Memoization Pattern
function memoize(fn) { const cache = {}; // Private cache return function(...args) { const key = JSON.stringify(args); if (key in cache) { console.log("Cache hit!"); return cache[key]; } console.log("Computing..."); const result = fn.apply(this, args); cache[key] = result; return result; }; } const expensive = memoize((n) => { console.log("Heavy computation..."); return n * n; }); console.log(expensive(5)); // Computing..., Heavy..., 25 console.log(expensive(5)); // Cache hit!, 25 (instant!)
Closures maintain private cache to store expensive computation results.
Common Mistakes
- Creating memory leaks by holding large objects in closures
- Not realizing closure variables are shared (not copied)
- Forgetting to clean up event listeners that use closures
Interview Tips
- Give concrete examples: data privacy, memoization, once function
- Explain the module pattern (IIFE + closure)
- Know when closures might cause memory leaks
- Show you understand practical applications