Según tengo entendido, si la variable de bucle de un bucle for se define con var , cualquier cambio en esa variable se aplica globalmente. por ejemplo:
var printNumTwo; for (var i = 0; i < 3; i++) { if (i === 2) { printNumTwo = function() { return i; }; } } console.log(printNumTwo());
En el código anterior, 3 se imprimirá en la consola. Porque en la última iteración, la variable i será igual a 3. Por lo tanto, cuando se llame a printNumTwo, se devolverá la actualización i . Sin embargo, si uso let, este no es el caso y ocurre el siguiente comportamiento:
let printNumTwo; for (let i = 0; i < 3; i++) { if (i === 2) { printNumTwo = function() { return i; }; } } console.log(printNumTwo());
El código anterior imprimirá 2.
let printNumTwo; for (let i = 0; i < 3; i++) { if (i === 2) { printNumTwo = function() { return i; }; i = 3; } } console.log(printNumTwo());
sin embargo, el código anterior imprime 3. ¿Cuál es la razón de esto?
sin embargo, el código anterior imprime 3. ¿Cuál es la razón de esto?
Porque asignas 3
a la variable i
que cierra printNumTwo
. No importa que la asignación ocurra después de que se crea printNumTwo
, solo que es la variable que está usando printNumTwo
.
La diferencia entre var
y let
in for
bucles es que se crea una nueva variable para el cuerpo del bucle en cada iteración de bucle con let
. Pero está asignando a esa variable dentro del cuerpo del ciclo, por lo que la función que se cierra ( printNumTwo
) ve ese valor más tarde cuando la llama.
Es exactamente así:
function create(i) { // This function closes over `i` const fn = function() { return i; }; // This modifies the `i` it closes over ++i; return fn; } const printValue1 = create(1); console.log(printValue1()); // 2 (1 + 1) const printValue27 = create(27); console.log(printValue27()); // 28 (27 + 1)
En respuesta a un comentario sobre la pregunta, has dicho:
Lo mismo también sucede en el segundo bloque de código (i++ en la sección de actualización en bucle for) pero la respuesta es 2
¡Ay! Ahora veo por qué hay un malentendido. Tienes razón en que hay una actualización de i
, pero no es la i
la que cierra printNumTwo
.
La sección de actualización del for
se realiza en la nueva variable para la siguiente iteración al comienzo de la siguiente iteración, no en la de la iteración que acaba de terminar al final de la iteración. Hace esto:
iNew
)iOld
) a la nueva variable ( iNew = iOld
)iNew
( iNew++
) Por eso i
(el viejo) sigue siendo 2
; es el nuevo que se convierte en 3
.
En el primer ejemplo, var
aplica i
a la función, por lo que al final del bucle i++
cambia i
de 2
a 3
y el bucle se detiene. La única i
ahora es 3
y printNumTwo
devuelve i
, que es 3
.
En el segundo ejemplo let
ámbitos i
en el bloque, por lo que la función asignada a printNumTwo
se cierra sobre él. La última vez que se ejecuta el cuerpo del bucle, i
es 2
y printNumTwo
devuelve i
, que es 2
. (Se crea una nueva i
con el valor 3
pero no se crea ninguna función que lo use).
En el tercer ejemplo, let
ámbitos i
en el bloque y sucede lo mismo excepto que tiene i = 3;
que cambia cada i
a 3
. Entonces, la última función que se crea (así como las anteriores que se sobrescriben) devuelve i
, que es 3
.
El alcance de var es la función y el alcance de let es el bloque.
Entonces, al asignar valor a la función printNumTwo
, el valor de i
sigue siendo 2. No importa lo que le suceda a i
más tarde.
El comportamiento de var y te permite entenderlo a partir de este ejemplo.
for(var i=0; i<3; i++){ setTimeout(() => console.log('var', i)) } for(let i=0; i < 3; i++){ setTimeout(() => console.log('let',i)) }