# Closures: Functions That Remember

A closure is a function together with the variables it could see where it was made, so it keeps using them after the function that made them has finished.

Journeyman · JavaScript · Updated November 1, 2026

## After this lesson you can

- Trace a closure step by step and predict what it returns
- Explain why functions made in a var loop share one variable, and fix the loop with let

## Key takeaways

- A function can make another function and return it, the same way it returns a number or a string.
- A closure is a function plus the variables it could see where it was written. It keeps them after the outer function has finished.
- Every call to the outer function makes a new set of variables, so each function it returns remembers its own.
- A closure remembers the variable itself, not a copy of its value, so it sees every later change.
- Functions made in a var loop all share one variable and see its last value. With let, each time around the loop gets its own.

A like button that remembers how many times it was clicked, a game that remembers its high score between rounds, a search box that waits until you stop typing: a lot of what makes an app feel alive is a function that remembers something. The tool that does it is called a **closure**. It's one of the ideas JavaScript is best known for, a favorite question in job interviews, and the reason a lot of code in libraries such as React works the way it does. This lesson takes it one step at a time.

## A function that makes a function

In *Functions as Values: Callbacks* you passed a function into another function. It works the other way too: a function can make a new function and **return** it, the same way it returns a number. A function that takes or returns another function is called a **higher-order function**.

```javascript
function makeGreeter(arcadeName) {
  return (player) => `Welcome to ${arcadeName}, ${player}!`;
}

const greet = makeGreeter('Starlight Arcade');

console.log(greet('Ava'));
console.log(greet('Leo'));
```

```text
Welcome to Starlight Arcade, Ava!
Welcome to Starlight Arcade, Leo!
```

`makeGreeter` runs once, returns the arrow function, and finishes. `greet` now holds that arrow function. Look closely at the output, though: when `greet` runs, `makeGreeter` is long finished, and its parameter `arcadeName` should be gone. Yet `greet` still knows it's the Starlight Arcade.

## A backpack: what a closure is

When a function is made, it packs a backpack with the variables it can see right there: the ones in the scopes around it. Wherever the function goes, it carries the backpack, and it can reach in any time it runs.

![A small arrow function wearing a backpack labeled arcadeName: Starlight Arcade. The function that made it has finished and faded out, but the backpack stays with the function.](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/10/33c1c5e616734474baf5ed06347bde26.webp)

That's a **closure**: a function together with the variables it could see where it was made. In JavaScript, every function is a closure; it only becomes noticeable when the function outlives the scope it was made in, as `greet` does. The rule behind it is called **lexical scope**: "lexical" means "to do with the words as written", so a function's scope is decided by where it's **written** in the code, not by where it's called from.

Normally, when a function finishes, its variables are thrown away. JavaScript has a cleanup crew, the **garbage collector**, that frees the memory of values nothing can reach anymore. A closure keeps its variables reachable, so the cleanup crew leaves them alone for as long as the closure is around.

## Step by step: a machine that remembers its high score

The Space Blaster machine keeps its high score between games. Here's a closure that does the same:

```javascript
function makeGameMachine(gameName) {
  let highScore = 0;

  return (points) => {
    if (points > highScore) {
      highScore = points;
    }
    return `${gameName} high score: ${highScore}`;
  };
}

const spaceBlaster = makeGameMachine('Space Blaster');

console.log(spaceBlaster(4200));
console.log(spaceBlaster(3100));
console.log(spaceBlaster(6800));
```

```text
Space Blaster high score: 4200
Space Blaster high score: 4200
Space Blaster high score: 6800
```

Follow it one step at a time:

1. `makeGameMachine('Space Blaster')` runs. It makes `gameName` (`'Space Blaster'`) and `highScore` (`0`).
2. It makes the arrow function, which packs `gameName` and `highScore` in its backpack, and returns it. `makeGameMachine` is finished.
3. `spaceBlaster(4200)`: 4200 is more than 0, so `highScore` becomes 4200.
4. `spaceBlaster(3100)`: 3100 isn't more than 4200, so `highScore` stays 4200.
5. `spaceBlaster(6800)`: a new high score, 6800.

The `highScore` variable lives on between calls, because the closure keeps it. And nothing outside can reach it: there's no way to write `spaceBlaster.highScore`, so no other code can change the high score by accident.

**Try it.** Save the code as `machine.js`, add a fourth game with 5000 points, and predict the line it prints before you run `node machine.js`.

## Every call packs a new backpack

Each time `makeGameMachine` runs, it makes a brand-new `highScore`, so every machine it returns remembers its own:

```javascript
function makeGameMachine(gameName) {
  let highScore = 0;

  return (points) => {
    if (points > highScore) {
      highScore = points;
    }
    return `${gameName} high score: ${highScore}`;
  };
}

const spaceBlaster = makeGameMachine('Space Blaster');
const pinball = makeGameMachine('Pinball Planet');

console.log(spaceBlaster(4200));
console.log(pinball(900));
console.log(spaceBlaster(1000));
```

```text
Space Blaster high score: 4200
Pinball Planet high score: 900
Space Blaster high score: 4200
```

Pinball's 900 doesn't touch Space Blaster's 4200. Two calls, two backpacks.

## It remembers the variable, not a copy

The backpack holds the variable itself, not a snapshot of its value. If the variable changes later, the closure sees the change:

```javascript
let tokensPerPlay = 2;

const priceSign = () => `Each game costs ${tokensPerPlay} tokens`;

console.log(priceSign());
tokensPerPlay = 3;
console.log(priceSign());
```

```text
Each game costs 2 tokens
Each game costs 3 tokens
```

`priceSign` reads `tokensPerPlay` each time it runs, so it shows whatever the variable holds right then. Keep this in mind for the next section: it explains a classic puzzle.

## The loop surprise: var and closures

Here's a puzzle that has confused programmers for years. A loop makes three functions, one for each prize booth, and puts them in an array. Each should announce its own booth:

```javascript
const boothSigns = [];

for (var booth = 1; booth <= 3; booth++) {
  boothSigns.push(() => `Prize booth ${booth} is open`);
}

console.log(boothSigns[0]());
console.log(boothSigns[1]());
console.log(boothSigns[2]());
```

```text
Prize booth 4 is open
Prize booth 4 is open
Prize booth 4 is open
```

Every function says booth 4, a booth that doesn't exist. Two things you already know explain it. A `var` belongs to the whole function or file, not to the loop, so there's only **one** `booth` variable, and all three functions packed that same one. And a closure remembers the variable, not its value. By the time the functions run, the loop has finished, and the loop only stopped when `booth` reached 4.

The fix is one word. With `let`, the loop makes a **new** `booth` each time around, so each function packs its own:

```javascript
const boothSigns = [];

for (let booth = 1; booth <= 3; booth++) {
  boothSigns.push(() => `Prize booth ${booth} is open`);
}

console.log(boothSigns[0]());
console.log(boothSigns[1]());
console.log(boothSigns[2]());
```

```text
Prize booth 1 is open
Prize booth 2 is open
Prize booth 3 is open
```

You'll meet the same puzzle whenever functions run after a loop has finished, such as timers and click handlers, and the fix is the same: `let`.

## Check yourself

2 questions to try on the lesson page.

## So what

A closure lets a function keep its own little memory, safe from the rest of the program. The next lesson, *Closures at Work: Private State and Factories*, puts that to work: counters nobody else can change, functions that build objects, and a function that can only run once.

## Key terms

- [Closure](https://www.ask-codey.com/glossary/closure-javascript)
- [Lexical Scope](https://www.ask-codey.com/glossary/lexical-scope)
- [Higher-Order Function](https://www.ask-codey.com/glossary/higher-order-function-javascript)
- [Garbage Collection](https://www.ask-codey.com/glossary/garbage-collection-javascript)

## Cheat sheets

- [Closures: Functions That Remember](https://www.ask-codey.com/cheat-sheets/javascript-closures-functions-that-remember-cheat-sheet)

## Related

- [Scope: Where a Variable Can Be Seen](https://www.ask-codey.com/lessons/javascript-scope-where-variables-live)
- [Closures at Work: Private State and Factories](https://www.ask-codey.com/lessons/javascript-closures-private-state-and-factories)

Source: https://www.ask-codey.com/lessons/javascript-closures-functions-that-remember
