Lección 30: Closures
🧠 Concepto
Section titled “🧠 Concepto”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.
Ejemplo clásico: Contador
Section titled “Ejemplo clásico: Contador”function crearContador() { let cuenta = 0; // variable "privada"
return { incrementar: () => ++cuenta, decrementar: () => --cuenta, obtenerValor: () => cuenta };}
const contador = crearContador();console.log(contador.obtenerValor()); // 0contador.incrementar(); // 1contador.incrementar(); // 2contador.decrementar(); // 1console.log(contador.obtenerValor()); // 1// No podemos acceder a 'cuenta' directamenteconsole.log(contador.cuenta); // undefined💻 Ejemplo
Section titled “💻 Ejemplo”// Fábrica de funcionesfunction multiplicador(factor) { return function(numero) { return numero * factor; };}
const duplicar = multiplicador(2);const triplicar = multiplicador(3);
console.log(duplicar(5)); // 10console.log(triplicar(5)); // 15
// Encapsulación con IIFEconst contadorUnico = (function() { let contador = 0; return function() { return ++contador; };})();
console.log(contadorUnico()); // 1console.log(contadorUnico()); // 2console.log(contadorUnico()); // 3⚠️ Nota
Section titled “⚠️ Nota”Un error común con closures ocurre en bucles con var:
// Mal: todas imprimen 3for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100);}
// Bien: closure por iteración con letfor (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.
📝 Ejercicio
Section titled “📝 Ejercicio”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"