Closures
A closure is a function plus the variables it captured from the scope where it was defined. They're how JavaScript keeps state without classes.
The simplest closure
JS
function counter() {
let count = 0;
return () => ++count; // captures `count`
}
const next = counter();
next(); // 1
next(); // 2
next(); // 3
count isn't visible outside counter — only the returned function can read or write it. That's encapsulation without classes.
Common patterns
Private state (module pattern)
JS
const auth = (() => {
let token = null;
return {
login(t) { token = t; },
logout() { token = null; },
isAuth() { return token !== null; },
};
})();
Memoization
JS
function memo(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (!cache.has(key)) cache.set(key, fn(...args));
return cache.get(key);
};
}
const slowAdd = memo((a, b) => a + b);
Once-only handler
JS
function once(fn) {
let called = false, result;
return (...args) => {
if (!called) { called = true; result = fn(...args); }
return result;
};
}
Loop gotcha (and the let fix)
JS
// ❌ var has one shared binding for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 0); // 3,3,3 // ✓ let creates a fresh binding per iteration for (let i = 0; i < 3; i++) setTimeout(() => console.log(i), 0); // 0,1,2
Tip: Closures keep their captured variables alive in memory. Avoid capturing huge objects in long-lived event listeners — they prevent garbage collection.
Example
Example
<!DOCTYPE html>
<html>
<body>
<p id="out"></p>
<script>
document.getElementById("out").textContent = "Hello from Closures!";
</script>
</body>
</html>
Try it Yourself »
Exercise
Make a counter that captures its private state.
function counter() { let count = 0; return () => ++
; }
The captured variable.
Discussion
Loading…