Comportamiento de las variables let declaradas dentro de un bucle for en el contexto de los closures.
En el siguiente fragmento de código, la función pasada a setTimeout
forma un cierre con la variable i
, la cual está presente en el alcance del script
. Por lo tanto, la función contiene una “referencia” a la variable i
. El valor de i
se actualiza a 5 antes de que se registre en la consola. Y la salida es: 5 5 5 5 5
(con saltos de línea).
script.js
:
let i;
for (i = 0; i < 5; ++i) {
setTimeout(() => {
console.log(i);
}, i * 1000);
}
La parte anterior me queda clara. Pero cuando declaro la variable i
“dentro” del bucle for
, entonces i
tiene un alcance de bloque limitado al bucle for
.
for (let i = 0; i < 5; ++i) {
setTimeout(() => {
console.log(i);
}, i * 1000);
}
En este fragmento de código, espero que la salida sea la misma que en el primer fragmento, porque el cierre contiene una “referencia” a la variable i
y el valor de esa “referencia” debería actualizarse a 5 antes de que se registre en la consola. Pero la salida real es: 0 1 2 3 4
(con saltos de línea).
La pregunta es, ¿por qué el código del segundo fragmento se comporta de esta manera?
¿Es porque:
1. Se crea una nueva copia de la variable i
en la memoria para cada iteración del bucle for
y la copia anterior se recoge como basura? No estoy seguro de cómo funciona la gestión de memoria en los bucles.
2. En lugar de almacenar una referencia de i
, ¿se almacena el “valor” de i
en el cierre? No creo que sea el caso.
3. ¿Algo más?
Por favor, ayúdame a aclarar esto. ¡Gracias!
davy.ai
La razón por la que el código en el segundo fragmento se comporta de manera diferente es porque cuando se usa
let
para declarari
dentro del buclefor
,i
tiene un alcance de bloque solo para el buclefor
. Esto significa que cada iteración del bucle tiene su propia instancia separada dei
. Cuando se llama a la funciónsetTimeout
en cada iteración, crea un cierre alrededor de la instancia dei
para esa iteración en particular, y no la variablei
en el ámbito exterior. Por lo tanto, cada llamada a la función registra el valor de la instancia separada dei
que se creó para esa iteración del bucle, lo que resulta en la salida0 1 2 3 4
.En resumen, la diferencia en el comportamiento de los dos fragmentos de código se debe a las reglas de alcance de
let
y la creación de una instancia separada dei
para cada iteración del bucle.