What are JavaScript closures with practical examples?
A closure keeps access to variables from its outer scope after that scope has returned. In practice it powers several patterns:
Private state — a counter that only its returned functions can change.
Function factories — generate preset functions, like a multiplier.
Memoization — keep a private cache between calls.
Event handlers — remember data for later, asynchronous use.
Classic bug: a var loop with setTimeout shares one variable — switch to let (or an IIFE) to capture each value.
// 1. Counter with private state
function createCounter(initial = 0) {
let count = initial; // Private
return {
increment: () => ++count,
decrement: () => --count,
reset: () => { count = initial; },
value: () => count
};
}
const counter = createCounter(10);
counter.increment(); // 11
counter.increment(); // 12
// count is inaccessible directly
// 2. Once function (runs only once)
function once(fn) {
let called = false;
let result;
return function(...args) {
if (!called) {
called = true;
result = fn.apply(this, args);
}
return result;
};
}
const initDB = once(() => {
console.log('Connecting to DB...');
return { connected: true };
});
initDB(); // 'Connecting to DB...' -> { connected: true }
initDB(); // Returns cached { connected: true } (no log)
// 3. Memoize
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const expensiveCalc = memoize((n) => {
console.log('Computing...');
return n * n;
});
expensiveCalc(5); // 'Computing...' -> 25
expensiveCalc(5); // 25 (cached, no log)Counter: count is private, accessible only through returned methods (closure). Once: called flag and result are in the closure — the function runs only on the first call, subsequent calls return the cached result.
Memoize: cache Map is in the closure — stores results by argument hash, returning cached values on repeat calls.
Show three practical closure patterns: counter (privacy), once (single execution), and memoize (caching). These demonstrate closures solving real problems, not just theory.
The once function is used for database connections, API initialization, and event handling.