Domina cómo las closures capturan variables para encapsular estado y evitar las trampas del ámbito.
Abrir esta lección en KodokonUna closure no es un truco exótico: es el mecanismo por el cual una función conserva el acceso al ámbito léxico donde fue definida, no aquel donde se la llama. El motor no copia los valores: mantiene una referencia viva al entorno léxico. Dos llamadas a la misma fábrica producen por tanto dos entornos independientes, lo que convierte a las closures en la herramienta de encapsulación más ligera del lenguaje.
function createCounter() {
let count = 0;
return {
increment: () => ++count,
reset: () => { count = 0; },
};
}
const counterA = createCounter();
const counterB = createCounter();
counterA.increment();
counterA.increment();
console.log(counterA.increment()); // 3
console.log(counterB.increment()); // 1La trampa clásica del mundo real: var está ligada a la función que la envuelve, no al bloque. Dentro de un bucle, cada closure captura entonces la misma variable. Con let, cada iteración crea un entorno léxico nuevo, por lo que cada captura es distinta. Añade a eso la zona muerta temporal (TDZ): una variable let o const existe desde que se entra en el bloque, pero lanza un ReferenceError si la lees antes de su declaración.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 3, 3, 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0); // 0, 1, 2
}En cuanto a patrones, las closures son la base de la memoización y del patrón módulo. Comparada con una clase, una closure te da privacidad genuina sin this ni prototipos, a costa de un uso de memoria ligeramente mayor cuando creas miles de instancias: cada instancia carga con sus propias funciones.
function memoize(fn) {
const cache = new Map();
return function (key) {
if (cache.has(key)) return cache.get(key);
const result = fn(key);
cache.set(key, result);
return result;
};
}
const square = (n) => n * n;
const fastSquare = memoize(square);
console.log(fastSquare(9)); // computed
console.log(fastSquare(9)); // read from the cachefor (var i = ...), ¿qué imprimen tres callbacks de setTimeout creados dentro del cuerpo del bucle?createCounter garantiza que count permanezca privada?