# Closures at Work: Private State and Factories

Put closures to work to keep a count that no other code can change, to build as many independent counters as you need with a factory function, and to make a function that runs only once.

Journeyman · JavaScript · Updated November 1, 2026

## After this lesson you can

- Write a factory function that keeps private state in a closure
- Write a wrapper function that lets another function run only once

## Key takeaways

- Any line in a file can change a variable at its top, even by mistake. A variable kept in a closure can change only through the functions that share it.
- Data kept this way is private state. Those functions are the only way in, so they can enforce the rules, such as never going below zero.
- A factory function makes and returns a new object each time it's called. Each object gets its own private variables.
- A wrapper function can keep a done flag in a closure, so the function it wraps runs only the first time.

A payment button that must never charge a card twice, however many times an impatient shopper clicks it. A game where every player has their own lives, and no bug in some other part of the code can hand out 99 of them. A shopping cart that only lets items in through an "add" button that checks the stock. Each of these needs data that only the right code can change, and closures are one of JavaScript's main tools for it. This lesson puts the closures from *Closures: Functions That Remember* to work.

## The trouble with a variable anyone can change

The arcade's Space Blaster gives each player 3 lives. Here they're kept in a variable at the top of the file:

```javascript
let lives = 3;

const loseLife = () => {
  lives = lives - 1;
};

loseLife();
lives = 99;
console.log(`Lives left: ${lives}`);
```

```text
Lives left: 99
```

`loseLife` is careful, but it isn't the only code that can reach `lives`. Any line in the file can, and here one does: maybe a typo, maybe a bug in a part of the program written months later. In a file of 30 lines you'd spot it. In a game of 3,000 lines, you'd spend an evening hunting for it.

## A lockbox: private state in a closure

Picture a lockbox with a few slots in its lid: one to drop a coin in, one to check the count. You can't open the lid; you can only use the slots. Move `lives` inside a function, and it becomes that lockbox. The function returns an object of small arrow functions (the slots), and they're the only code that can reach the variable, because they're the only code written in its scope:

```javascript
function makeLivesCounter() {
  let lives = 3;

  return {
    loseLife: () => {
      if (lives > 0) {
        lives = lives - 1;
      }
      return lives;
    },
    extraLife: () => {
      lives = lives + 1;
      return lives;
    },
    livesLeft: () => lives,
  };
}

const ava = makeLivesCounter();
ava.loseLife();
ava.loseLife();
ava.extraLife();
console.log(`Lives left: ${ava.livesLeft()}`);
console.log(ava.lives);
```

```text
Lives left: 2
undefined
```

The three arrow functions are closures: they all carry the same `lives` in their backpack. `ava.lives` is `undefined`, because the object has no property by that name; the variable lives in the closure, not in the object. Data that only its own functions can reach is called **private state** ("state" is the values a thing holds right now), and keeping data behind the functions that change it is called **encapsulation**.

Being the only way in is what makes the functions useful: `loseLife` checks `lives > 0`, so the count can never go below zero, and no other code can get around that rule.

## A factory: one function, many players

`makeLivesCounter` is a **factory function**: a function that makes and returns a new object each time it's called, the way a factory turns out one toy after another from the same mold. Each call runs the function again, so each object gets its own private variables. A parameter lets each one start differently:

```javascript
function makeLivesCounter(startingLives) {
  let lives = startingLives;

  return {
    loseLife: () => {
      if (lives > 0) {
        lives = lives - 1;
      }
      return lives;
    },
    livesLeft: () => lives,
  };
}

const ava = makeLivesCounter(3);
const leo = makeLivesCounter(5);

ava.loseLife();
ava.loseLife();
ava.loseLife();
ava.loseLife();
leo.loseLife();

console.log(`Ava: ${ava.livesLeft()}, Leo: ${leo.livesLeft()}`);
```

```text
Ava: 0, Leo: 4
```

Ava lost four lives but stops at 0, and Leo's count is untouched by any of it. Ten players, ten calls, ten lockboxes. (The next chapter, *Objects, Classes and this*, shows the other way JavaScript builds many objects from one design: classes.)

**Try it.** Save the code as `lives.js`, add an `extraLife` function to the object, give Leo an extra life, and run `node lives.js`. Leo should end with 5.

## A function that runs only once

The arcade hands each new player a coupon for one free game. The coupon must work the first time and never again. A closure can remember whether it has been used:

```javascript
function makeFreePlayCoupon(game) {
  let used = false;

  return () => {
    if (used) {
      return 'This coupon has already been used';
    }
    used = true;
    return `One free game of ${game}!`;
  };
}

const redeem = makeFreePlayCoupon('Space Blaster');

console.log(redeem());
console.log(redeem());
console.log(redeem());
```

```text
One free game of Space Blaster!
This coupon has already been used
This coupon has already been used
```

The same idea works for **any** function. A **wrapper** is a function that takes another function and returns a new one that adds something around it. This one adds "only the first time": it keeps a `done` flag in its closure, and calls the function it was given only while `done` is still `false`.

```javascript
function once(action) {
  let done = false;

  return () => {
    if (!done) {
      done = true;
      action();
    }
  };
}

const ringBell = () => console.log('Ding! A new high score!');
const ringBellOnce = once(ringBell);

ringBellOnce();
ringBellOnce();
ringBellOnce();
console.log('The game goes on.');
```

```text
Ding! A new high score!
The game goes on.
```

`!done` is read "not done": it's `true` while `done` is still `false`. The bell rings once, however many times `ringBellOnce` is called. A real payment button does exactly this, so a double click charges the card one time. This version throws away whatever `action` returns; in *Exercise: Arcade Token Counters* you'll write a `once` that remembers the first result and hands it back every time.

## Check yourself

2 questions to try on the lesson page.

## So what

Private state, factories and run-once functions are closures doing real work: keeping data safe, making many independent copies, and enforcing rules no other code can skip. You'll meet the same patterns in event handlers, in libraries such as React, and later in this course in debounce, which waits for you to stop typing before it searches.

## Key terms

- [Closure](https://www.ask-codey.com/glossary/closure-javascript)
- [Encapsulation](https://www.ask-codey.com/glossary/encapsulation-javascript)
- Factory Function
- [State](https://www.ask-codey.com/glossary/state)

## Cheat sheets

- [Closures at Work: Private State and Factories](https://www.ask-codey.com/cheat-sheets/javascript-closures-private-state-and-factories-cheat-sheet)

## Related

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

Source: https://www.ask-codey.com/lessons/javascript-closures-private-state-and-factories
