← JavaScript

Scope & Hoisting

What is a closure and what is it used for?

Show answer — try answering out loud first

A closure is a function that "remembers" the variables of the scope where it was created, even after that scope has finished executing. It is useful for keeping private state and for creating configurable functions.

When you define a function inside another one, the inner function keeps access to the outer function's variables. Even though the outer function has already finished, the inner one keeps "remembering" those variables. That combination of function + remembered variables is called a closure.

It is one of the fundamentals of JavaScript. It is used to:

  • Keep private state (variables that only the function can touch).
  • Create functions from other functions (function factories).
  • Callbacks, event handlers, etc.
// Counter with private state thanks to the closure
function crearContador() {
  let cuenta = 0; // this variable stays "enclosed"
  return function () {
    cuenta++;
    return cuenta;
  };
}

const contador = crearContador();
console.log(contador()); // 1
console.log(contador()); // 2
console.log(contador()); // 3
// "cuenta" is not accessible from outside: it is private

// Function factory: each one remembers its own "factor"
function multiplicarPor(factor) {
  return function (numero) {
    return numero * factor;
  };
}

const duplicar = multiplicarPor(2);
const triplicar = multiplicarPor(3);
console.log(duplicar(5)); // 10
console.log(triplicar(5)); // 15

The classic for loop bug with var:

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}
// Prints 3, 3, 3 (not 0, 1, 2)

With var, all the functions share the same i, which ends up being 3. The solution is to use let, which creates a new variable per iteration, and each closure remembers its own.

"A closure is a function that remembers the variables of the scope where it was created, even after that scope has finished. For example, if I have a function that returns another function, the returned function still has access to the variables of the first one. This lets me keep private state, like a counter whose variable cannot be modified from outside, or create configurable functions like a multiplicarPor(2)."

Quick challenge

Create a function crearSaludo(saludo) that returns another function which takes a name and returns the full greeting. Example: crearSaludo("Hola")("Mike") should return "Hola, Mike".

See answer
function crearSaludo(saludo) {
  return function (nombre) {
    return `${saludo}, ${nombre}`;
  };
}
console.log(crearSaludo("Hola")("Mike")); // "Hola, Mike"