Closures: functions that remember where they were made
A closure is a function plus the variables around it. Use closures for private state, understand the var-in-a-loop trap, and write once().
Comes up in: JavaScript, Coding, Recruiter screen
Learn#
Deepa builds a “Pay now” button. Users double-click, and some are charged twice. She needs a function that can run only once — which means a function that remembers whether it already ran.
Functions in JavaScript remember. A function keeps a link to the scope it was created in, and can use those variables even after that scope’s function has returned. A function together with those remembered variables is a closure.
That gives you private state: data only the returned function can reach.
function makeCounter() {
let count = 0;
return () => ++count;
}
const next = makeCounter();
console.log(next(), next(), next());
for (var i = 0; i < 3; i++) setTimeout(() => console.log("var:", i));
for (let j = 0; j < 3; j++) setTimeout(() => console.log("let:", j));Output (verified)
1 2 3 var: 3 var: 3 var: 3 let: 0 let: 1 let: 2
The loops show the famous trap. var i is one variable for the whole function, so all three callbacks remember the same i, which is 3 by the time they run. let j creates a new variable for each loop turn, so each callback remembers its own.
makeCounter scope
- count = 0
Call stack
- makeCounter
Console
empty
makeCounter runs and creates count = 0 in its scope.
Read the steps as text
- makeCounter runs and creates count = 0 in its scope.
- It returns the arrow function. makeCounter's call ends, but the arrow still links to its scope.
- next() runs the arrow. It finds count through its saved link and adds 1.
- Each call changes the same count. Nothing outside can reach it.
Predict#
Predict first
Two counters: const a = makeCounter(); const b = makeCounter(); a(); a(); What does b() return?
Every call to makeCounter creates a new scope with a new count. a and b remember different scopes, so b() starts from 0 and returns 1. Sharing only happens when closures come from the same call — like the var loop.
Interview angle#
Say it like this — about 30 seconds
“A closure is a function plus the variables of the scope where it was created. The function keeps a reference to that scope, so it can read and change those variables after the outer function has returned. I use closures for private state — counters,
once, memoize caches — and for callbacks that need local data. The classic trap isvarin a loop: all callbacks share one variable.letfixes it by creating a new binding each iteration.”
Follow-up What does for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)) print, and how do you fix it?
let i, with an IIFE that takes i as a parameter, or by passing i as an extra argument to setTimeout.Follow-up Implement a function that can be called only once.
called and result in a closure; on the first call run fn and store the result; later calls return the stored result.Follow-up What is a stale closure in React?
Practice#
On your own
Write once(fn) — the fix for Deepa’s double charge.
Done when
fnruns on the first call only; later calls return the first result.- Arguments and
thisreachfn. - Two
oncewrappers do not share state.
Remember#
Try to answer each card before you open it. Then add them to your reviews.
What is a closure?
A function together with the variables of the scope where it was created.
What does this print?for (var i = 0; i < 3; i++) setTimeout(() => console.log(i));
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i));3 3 3
Why does let fix the loop-and-setTimeout trap?
let creates a new binding for each loop iteration.
Name two practical uses of closures.
Private state (counters, once) and caches (memoize); also callbacks that need local data.
Go deeper
Four layers. Stop at the one your interview needs; each ends with a quick check.
The core ideaEvery round
A closure keeps the variable, not a copy of its value. If the variable changes later, the closure sees the new value. That is both why counters work and why the var loop prints 3 three times.
Check yourself: Does a closure copy the variable's value or keep the variable itself?
It keeps the variable itself, so it sees later changes.
How it works underneathSenior rounds
When a function is created, the spec stores the current environment in its [[Environment]] slot. Each call creates a new environment whose outer link is that saved one Source: ECMA-262: OrdinaryFunctionCreate. For let loops, the spec copies the loop variable into a fresh environment each iteration Source: ECMA-262: CreatePerIterationEnvironment.
Check yourself: Where does a function store the scope it was created in?
In its internal [[Environment]] slot.
Edge cases and trapsWhere people slip
Before modules, libraries used an IIFE — an immediately invoked function expression, (function () { … })() — to keep their variables private and expose only what they returned. That is the “module pattern”. Today ES modules give each file its own scope, so IIFEs are rarely needed.
Check yourself: What is an IIFE?
A function expression that is called immediately, creating a private scope.
In productionStaff-level answers
React components are functions that run on every render, and each render’s handlers close over that render’s state. A timer or effect that keeps an old handler reads old state — a stale closure. The fixes are updater functions, correct effect dependencies, or refs (RCT.04.03).
Check yourself: Why can an event handler created in an old React render show old state?
It is a stale closure: it remembers the variables from the render that created it.
Finished the five steps? Mark it, and its cards join your reviews.
Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.
Interview questions this answers
- What is a closure? Give a practical use.
- What will
for (var i=0;i<3;i++) setTimeout(()=>console.log(i))print? How do you fix it? - Implement a function that can be called only once.