Skip to content
Sahil Durgia/ full-stack
1 min readJavaScript

Closures Explained With Real, Non-Toy Examples

A closure isn't a trick question — it's how every debounce function, every useState, and every module pattern in JavaScript actually works under the hood.

JavaScriptclosuresfundamentals

A closure is a function that remembers the variables from the scope it was created in, even after that outer scope has finished running. That's the whole definition — the reason it feels slippery is that most explanations stop at the definition instead of showing why it's load-bearing in real code.

The minimal example

function makeCounter() {
  let count = 0;
  return () => ++count;
}
const counter = makeCounter();
counter(); // 1
counter(); // 2 — count persisted between calls, with no global variable

The example that actually shows why it matters: debounce

Every debounce implementation you've ever used — a search box that waits for typing to pause before firing a request — is a closure holding onto a `timeoutId` between calls.

function debounce(fn, delay) {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn(...args), delay);
  };
}
const onSearch = debounce((q) => fetchResults(q), 300);

`timeoutId` lives in the outer function's scope, and the returned function closes over it. Every call to the debounced function reads and writes the same `timeoutId`, across calls, with no module-level variable and no class instance — that persistence is the closure doing its job.

Why this is also how React hooks work

`useState` doesn't use magic — a component function closes over the state React hands it on each render, and the setter function you get back closes over the mechanism to schedule the next render. Once closures make sense, hooks stop looking like framework magic and start looking like an application of a language feature you already understand.

Runnable example

The snippets above are the short version — the full, runnable code lives on GitHub.

View on GitHub ★
Keep reading
Next: prototypal inheritance

Part 6 of the JavaScript fundamentals series.