JavaScript closures explained by someone who actually uses them
·2 min read ·JavaScript · Programming · Fundamentals
Closures get introduced in JavaScript courses right before the interviewer asks you to explain them. They feel academic. They aren't—I use closures constantly in production code.
What a Closure Actually Is
A closure is a function that remembers the variables from the scope where it was defined, even after that scope has closed.
function createCounter() {
let count = 0; // This variable is 'closed over'
return {
increment: () => ++count,
decrement: () => --count,
value: () => count,
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
counter.value(); // 1
count is private to the closure. Nobody can access it directly. This is how you get encapsulation in JavaScript without classes.
Memoization
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) => {
// Heavy computation...
return result;
});
The cache Map is closed over by the returned function. It persists across calls without being a global variable.
The Classic Trap
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// Prints: 3, 3, 3 (not 0, 1, 2)
All three callbacks close over the same i. By the time they run, the loop has finished and i is 3. Use let instead of var and each iteration gets its own block-scoped i.
Closures are everywhere once you know to look: React hooks, event handlers, module patterns, partial application. They're not a trick—they're a fundamental building block.