Si los argumentos a las funciones se pasan por valor en javascript, ¿cómo es que console.log() a continuación parece obtener su entrada por referencia? ¿No debería cada vez que se invoca dentro de setTimeout solo pasar el valor de i y no su referencia?
let i; for (i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); }, i * 1000); }¿No debería cada vez que se invoca dentro de setTimeout solo pasar el valor de i y no su referencia?
Sí, y esto es exactamente lo que está sucediendo. Está pasando el valor de i por valor a console.log(i) . Pero, está pasando ese valor DESPUÉS de que se haya completado todo el ciclo for cuando i su valor terminal porque este es el orden en que se ejecutan las cosas:
let i .for .for se ejecuta hasta el final, cada iteración inicia un temporizador adicional. El temporizador no bloquea y es asíncrono, por lo que simplemente inicia el temporizador y continúa la ejecución del bucle.for esté completamente terminado) con el valor de i sentado en su valor de terminal, los temporizadores comienzan a dispararse, lo que hace que llamen a su devolución de llamada y luego console.log(i) . Tenga en cuenta que si hiciera que let i sea parte de la declaración del bucle for , obtendría resultados completamente diferentes:
for (let i = 1; i <= 5; i++) { // Because let i was inside the for loop declaration, // there is a separate copy of i for each iteration of the for loop here setTimeout(function timer() { console.log(i); }, i * 1000); } Porque aquí hay un tratamiento especial para let i en el bucle for . Cada iteración del ciclo obtiene su propia copia separada de i y, por lo tanto, todavía tiene el valor que tenía cuando se ejecutó la iteración del ciclo en el momento posterior en que se activa el temporizador.
Esto es completamente diferente a su versión original donde solo hay una i para todo el ciclo y su valor se incrementa en cada iteración y, por lo tanto, el valor i tenía cuando se ejecutó cada iteración del ciclo ya no está disponible cuando se activa el temporizador.
for (let i=1; i<=5; i++) { setTimeout( function timer(){ console.log( i ); }, i*1000 ); }Esto tiene que ver con un concepto muy importante llamado alcance . Un alcance es la pieza de código donde existe su variable.
En su ejemplo, define la variable antes del bucle for. Así que esto sucede internamente:
En mi ejemplo, tengo el alcance en el bucle for. Esto significa que cada iteración del bucle genera una nueva referencia a i. Entonces, estas referencias se refieren a diferentes variables desde el punto de vista de las computadoras (incluso si su código las nombra todas).
for (let i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); }, i * 1000); }