Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Asynchronous JavaScript  ›  Lesson

Closures

Closures 12 minA closure is a function bundled with the scope it was born in, carried along like a backpack, so it can keep reading and changing those variables long after the outer function has returned — and each call to the outer function packs a fresh, separate backpack.

Closures

In short: a closure is a function bundled together with the scope it was born in — a backpack of variables it carries along wherever it goes, even long after the outer function that created it has already returned. Every separate call to the outer function packs a separate backpack, so two functions made the same way never accidentally share state. Closures are how JavaScript gives you private variables with no special syntax at all.

makeCounter() with let count = 0 returns an inner function that packs count into a backpack; the backpack (count, private, carried along) travels with the function to wherever it's later called, far away — a note that two calls to makeCounter() pack two SEPARATE backpacks, and that var in a loop shares one backpack while let packs a fresh one each lap

A private counter, with no class needed

Each call to makeCounter creates its own count, sealed inside the returned function:

javascript

counter1 and counter2 each close over their own count — calling counter1() twice doesn't touch counter2's backpack at all. There's no way to reach count directly from outside; the only access is through the function that was handed back.

Configured functions, built once and reused

Closures are perfect for "bake in some settings, then use the result many times":

javascript

tenPercentOff and halfOff are both ordinary functions on the outside — you just call them with a price. But each one carries its own rate in its backpack, fixed forever at the moment it was created.

The classic trap: var in a loop

This is the single most common closure bug, and it comes down to what gets packed into the backpack:

javascript

With var, there's only one i for the whole loop — every function packs a backpack pointing at that same shared i, which is 3 by the time the loop ends, so every call returns 3. With let, each lap of the loop gets its own fresh i, so each function's backpack holds a different value: 0, 1, 2. This is one of the strongest everyday reasons to prefer let over var.

Quick practice

quick drill

What does a closure let a function keep access to, even after the outer function has returned?

quick drill

In the makeDiscounter example, do tenPercentOff and halfOff share the same rate variable?

quick drill

Why does the var version of the loop example return 3, 3, 3 instead of 0, 1, 2?

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainThe var-in-a-loop trap
function makeLoggersVar() {
  const fns = [];
  for (var i = 0; i < 3; i++) {
    fns.push(function () { return i; });
  }
  return fns;
}

Every function in the returned array returns 3, not 0, 1, 2. Explain why, and why switching var to let fixes it.