← Frontend interview questions
Closures Interview Questions
Closures are the language feature interviewers use to see whether you understand lexical scope under pressure—not whether you can recite a textbook definition. In real apps they show up in event handlers that outlive their creators, debounced inputs, animation frames, and the subtle moment a callback closes over a stale variable and ships the wrong ID to an API. Your answers should sound like debugging war stories, not flashcards.
Classic traps—and how seniors describe fixes
- Loop + async: why a classic
forloop withvarsurprises people, whyletworks, and when you reach for an IIFE,.mapwith an argument, or a factory function—use the explanation style you actually use in code review. - Timers and subscriptions: closures holding references that prevent garbage collection; cleaning up in useEffect returns or explicit dispose methods.
- Partial application: when currying clarifies configuration and when it obscures call sites—say you optimize for the next reader.
Modules and bundlers
Closures underpin module scope. If you have debugged duplicate singletons from double bundling or hot reload quirks, mention it—interviewers like engineers who connect language semantics to toolchain reality.
Next steps on this site
Tighten the React angle with React Hooks, then zoom out to JavaScript interview prep for language-wide async and module questions that often follow closure prompts.
The timer bug every Azure Functions + portal team hits once
Stale closure with setInterval (fixed with ref or functional updates)
function usePolling(fetcher: () => Promise<void>, ms: number) {
const latest = useRef(fetcher);
latest.current = fetcher;
useEffect(() => {
const id = setInterval(() => latest.current(), ms);
return () => clearInterval(id);
}, [ms]);
}First version closes over fetcher from mount—your Storage Queue depth never updates. Ref indirection is the human story: "always call the newest function without rescheduling the clock." That is senior closure talk without sounding academic.
Questions with sample answers
These are interview-ready outlines—sound human by swapping in your own metrics, team names, and war stories. The examples are generic on purpose so you can map them to what you actually shipped.
Primary prompt
Show how a closure captures loop variables—then fix it three different ways.
Classic
varin loop +setTimeoutprints same final i. Fixes:letper iteration block scope; IIFE passing i;forEachwith callback arg.Primary prompt
Explain module scope vs function scope with an example from a bundler-split codebase.
Module top-level singleton shared across importers (one instance per bundle); function scope per call—two copies of module if duplicated in chunks can mean two singletons—watch dedupe in Vite/webpack.
Primary prompt
How do closures interact with garbage collection in long-lived SPAs?
Inner function holding reference to large outer scope prevents GC—detach listeners, null refs, avoid accidental captures in hot paths.
Primary prompt
Write a tiny memoize(fn) using a closure—what are the memory trade-offs?
const cache = new Map()inside returned function—unbounded cache grows forever; cap size (LRU) or use WeakMap for object keys only.
Follow-ups interviewers often ask
Expect nested "why?" questions—brief answers here; expand with your production defaults.
Follow-up
What is the temporal dead zone and when does it bite in real code?
let/constnot hoisted to usable value before declaration—errors accessing before line; shows up copying var patterns to let across refactors.Follow-up
How do arrow functions change `this` behavior compared to function declarations?
Arrows lexically bind
this—good for callbacks; bad when you need dynamic this—use regular function for class methods if not bound.Follow-up
When would you avoid closures for performance or debugging clarity?
Hot loops allocating many closures; debugging deep closure chains—sometimes inline or module-level named functions clearer.
Follow-up
How does hot module replacement interact with module-level state?
State may reset or persist depending on HMR boundary—document quirks; use
import.meta.hotaccept handlers to preserve critical state in dev.Follow-up
Describe a stale closure bug in React hooks and the idiomatic fix.
Effect captures old
countbecause deps missing—fix deps array or functional updatersetCount(c => c + 1); use ref for latest value in intervals.