~/ 👨‍💻 uncodigo.com _


Closures en JavaScript: Qué son y por qué todos los usan

Por Felipe el
Una explicación clara y práctica sobre los closures en JavaScript, con ejemplos del mundo real y patrones de uso comunes.

Los closures son una de las características más elegantes y poderosas de JavaScript 🧠. Permiten que las funciones “recuerden” el entorno en el que fueron creadas, incluso después de que ese contexto haya desaparecido. En otras palabras: una función puede acceder a variables externas aunque su ámbito original ya no exista.

🔍 ¿Qué es un closure exactamente?

Un closure ocurre cuando una función interna “cierra” sobre las variables de su función externa. Esto le permite mantener acceso a ellas incluso después de que la función externa haya terminado de ejecutarse.

function crearContador() {
  let cuenta = 0;

  return function () {
    cuenta++;
    console.log(`Contador: ${cuenta}`);
  };
}

const contador = crearContador();

contador(); // Contador: 1
contador(); // Contador: 2
contador(); // Contador: 3

👉 La variable cuenta no se borra cuando crearContador() termina. La función interna sigue “recordándola”. Ese es el closure en acción.

🧩 Cómo funciona paso a paso

  1. Se ejecuta crearContador(), creando una variable local cuenta = 0.
  2. crearContador() devuelve una nueva función que usa cuenta.
  3. Aunque crearContador() ya terminó, la función devuelta mantiene una referencia viva al entorno donde fue creada.

📦 En resumen: un closure es una función + su entorno léxico (las variables que estaban a su alcance cuando se creó).

⚙️ Otro ejemplo clásico: funciones personalizadas

function saludar(nombre) {
  return function(saludo) {
    console.log(`${saludo}, ${nombre}!`);
  };
}

const saludaFelipe = saludar('Felipe');
const saludaMarta = saludar('Marta');

saludaFelipe('Hola'); // Hola, Felipe!
saludaMarta('Buenos días'); // Buenos días, Marta!

Aquí cada función conserva su propio contexto. nombre no se pierde porque está dentro del closure.

🧠 Por qué los closures son útiles

Los closures se usan todo el tiempo, incluso si no te das cuenta. Veamos algunos usos comunes:

UsoDescripciónEjemplo
EncapsulaciónPermiten crear variables privadas que no son accesibles desde fuera.Contadores, módulos, control de acceso.
CallbacksRetienen el estado entre ejecuciones asíncronas.Eventos, setTimeout, fetch.
CurryingPreconfiguran funciones para ser reutilizadas con distintos argumentos.const sumar5 = x => sumar(5, x);

🔒 Encapsulación y variables privadas

Antes de class y #private, los closures eran la forma más popular de proteger variables.

function crearBanco(saldoInicial) {
  let saldo = saldoInicial;

  return {
    depositar(cantidad) {
      saldo += cantidad;
      console.log(`Depositaste $${cantidad}. Saldo: $${saldo}`);
    },
    retirar(cantidad) {
      if (cantidad > saldo) {
        console.log('Fondos insuficientes 🚫');
        return;
      }
      saldo -= cantidad;
      console.log(`Retiraste $${cantidad}. Saldo: $${saldo}`);
    }
  };
}

const miCuenta = crearBanco(100);
miCuenta.depositar(50);  // Depositaste $50. Saldo: $150
miCuenta.retirar(70);    // Retiraste $70. Saldo: $80

console.log(miCuenta.saldo); // ❌ undefined

💡 saldo está “protegido” dentro del closure — solo se puede acceder a él a través de las funciones devueltas.

⚡ Closures y setTimeout

Un caso clásico de uso (y confusión) con closures ocurre en bucles:

for (var i = 1; i <= 3; i++) {
  setTimeout(() => console.log(i), 1000);
}
// Resultado: 4, 4, 4 ❌

Esto pasa porque var no tiene ámbito de bloque, y todas las funciones dentro del bucle comparten el mismo i.

✅ Solución con let o closure explícito:

for (var i = 1; i <= 3; i++) {
  (function(x) {
    setTimeout(() => console.log(x), 1000);
  })(i);
}
// Resultado: 1, 2, 3 ✅

🧩 Buenas prácticas con closures

✅ Úsalos para encapsular datos sin recurrir a clases. ✅ Evita abusar de ellos en estructuras muy anidadas (puede dificultar la lectura). ✅ Recuerda que mantener referencias vivas puede generar fugas de memoria si no se limpian correctamente.

🎯 Conclusión

Los closures son uno de los pilares del lenguaje. Entenderlos te permite dominar conceptos más avanzados como módulos, funciones puras, currying y patrones funcionales.

Un closure no solo recuerda variables… también recuerda tu nivel de JavaScript 😉