Skip to content

JavaScript closures explained simply

October 31, 2026 · 2 min read

A closure is a function that keeps access to the variables from the place it was written, even after the outer function has finished. That is how a function can "remember" a value between calls.

Build a counter factory

function makeCounter() {
  let count = 0;
  return () => {
    count += 1;
    return count;
  };
}

const orders = makeCounter();
const returns = makeCounter();

console.log(orders());
console.log(orders());
console.log(returns());
console.log(orders());

Output:

Output
1
2
1
3

What is happening

  • makeCounter() creates a count variable and returns the inner arrow function.
  • makeCounter has finished running, but the inner function still uses count, so JavaScript keeps it alive. The function plus the variables it remembers is the closure.
  • Each call to makeCounter() creates a fresh count. That is why returns() starts at 1 while orders() carries on.
  • Nothing outside can touch count. The only way to change it is to call the function, which makes it private state.

Closures are also handy for settings. A factory can bake in a value, such as a tax rate, so each function it returns carries its own:

function makePricer(taxRate) {
  return (price) => (price * (1 + taxRate)).toFixed(2);
}

const withVat = makePricer(0.2);
const withSalesTax = makePricer(0.08);

console.log(withVat(50));      // 60.00
console.log(withSalesTax(50)); // 54.00

Each pricer remembers the taxRate it was created with, and the two never interfere.

Common mistake

Creating functions in a loop with var. A var belongs to the whole function, so every inner function shares one variable:

const fns = [];
for (var i = 0; i < 3; i++) fns.push(() => i);
console.log(fns.map((f) => f()));   // [ 3, 3, 3 ]

Use let instead. It gives each pass of the loop its own variable:

const ok = [];
for (let j = 0; j < 3; j++) ok.push(() => j);
console.log(ok.map((f) => f()));    // [ 0, 1, 2 ]

Takeaway

When an inner function uses a variable from its outer function, it keeps that variable after the outer function returns. Call the outer function again and you get a new, separate copy.

More on JavaScript & TypeScript