Closures & private state

Functions that remember

Lesson 1 of 20 · 10 min · Module 1: Functions, deeper

A function created inside another function keeps access to the variables around it, even after the outer function has finished. That is called a closure, and it is how JavaScript keeps data private without classes.

Start this lesson →

Free. No installation: you write and run the code in your browser, and it is checked automatically.

By the end, you’ll be able to…

  • Explain what a closure is
  • Keep state private inside a function
  • Create independent instances with a factory function

The idea

Each call of the outer function creates new variables, and the inner functions it returns share exactly those variables. Nothing outside can read or change them except through the functions you return.

function makeGreeter(greeting) {
  return name => greeting + ", " + name + "!";
}

const hello = makeGreeter("Hello");
console.log(hello("Mia"));

01Functions carry their surroundings

When makeGreeter returns the arrow function, the variable greeting stays alive because the arrow function still uses it. Every function in JavaScript remembers the scope it was created in.

02One call, one private world

Each call of createCounter makes a new current variable. The next and reset functions returned by that call share it, but a second counter gets its own.

function makeCounter() {
  let count = 0;
  return () => ++count;
}
const a = makeCounter();
const b = makeCounter();
console.log(a(), a(), b());
Output
1 2 1

03Private by design

Because current is a local variable and not a property, Object.keys(counter) only shows next and reset. Other code cannot set the counter to a wrong value by accident.

Your turn

Write createCounter(start = 0, step = 1). It returns an object with next(), which returns start on the first call, then start + step, and so on, and reset(), which makes the next call of next() return start again. Two counters must be independent, and the current value must not be visible as a property.

What the checks look for

  • Counts from the default start
  • Uses a custom start and step
  • reset() starts over
  • Counters are independent and keep their value private
Try it in the editor →

Take this with you

A closure is a function plus the variables it remembers.

Go a little further

Add a peek() method that returns the last value without advancing the counter.

Learn JavaScript Intermediate for free

20 short lessons with real code and instant checks.

See the whole course →