Skip to content

Lección 30: Closures

Un closure es una función que “recuerda” las variables del ámbito externo incluso después de que la función externa haya terminado de ejecutarse. Es el concepto más importante de JavaScript.

Definición formal: Un closure se crea cuando una función interna accede a variables de su función externa y esa función interna se “exporta” al ámbito exterior.

function crearSaludo(saludo) {
// Esta función interna "recuerda" el parámetro saludo
return function(nombre) {
console.log(`${saludo}, ${nombre}`);
};
}
const saludarHola = crearSaludo('Hola');
const saludarChao = crearSaludo('Chao');
saludarHola('Ana'); // "Hola, Ana"
saludarChao('Luis'); // "Chao, Luis"

Aquí, saludo ya no existe después de ejecutar crearSaludo, pero las funciones devueltas lo recuerdan gracias al closure.

function crearContador() {
let cuenta = 0; // variable "privada"
return {
incrementar: () => ++cuenta,
decrementar: () => --cuenta,
obtenerValor: () => cuenta
};
}
const contador = crearContador();
console.log(contador.obtenerValor()); // 0
contador.incrementar(); // 1
contador.incrementar(); // 2
contador.decrementar(); // 1
console.log(contador.obtenerValor()); // 1
// No podemos acceder a 'cuenta' directamente
console.log(contador.cuenta); // undefined
// Fábrica de funciones
function multiplicador(factor) {
return function(numero) {
return numero * factor;
};
}
const duplicar = multiplicador(2);
const triplicar = multiplicador(3);
console.log(duplicar(5)); // 10
console.log(triplicar(5)); // 15
// Encapsulación con IIFE
const contadorUnico = (function() {
let contador = 0;
return function() {
return ++contador;
};
})();
console.log(contadorUnico()); // 1
console.log(contadorUnico()); // 2
console.log(contadorUnico()); // 3

Un error común con closures ocurre en bucles con var:

// Mal: todas imprimen 3
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Bien: closure por iteración con let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 0, 1, 2
}
// O con IIFE (para var)
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i); // 0, 1, 2
}

Los closures son la base de:

  • Encapsulación (variables privadas)
  • Fábricas de funciones (generar funciones con configuraciones)
  • Módulos (patrón IIFE)
  • Callbacks y event handlers (preservar estado)
  • Currying (transformar funciones multi-parámetro en cadenas)

Si entiendes closures, entiendes JavaScript.

Crea una función crearAcceso(nivel) que devuelva un objeto con métodos leer(), escribir() y admin(). Cada método debe estar disponible solo si el nivel de acceso lo permite: 'usuario' solo puede leer, 'editor' puede leer y escribir, 'admin' puede todo.

function crearAcceso(nivel) {
// Escribe aquí
}
const usuario = crearAcceso('usuario');
const admin = crearAcceso('admin');
console.log(usuario.leer()); // "Leyendo..."
console.log(usuario.escribir()); // "Sin permiso"
console.log(admin.admin()); // "Acceso total"