tengo este codigo:
function makeArmy() { let shooters = []; let i = 0; while (i < 10) { let shooter = function () { console.log(i); // that should show its number }; shooters.push(shooter); // and add it to the array i++; } // ...and return the array of shooters return shooters; } let army = makeArmy(); // all shooters show 10 instead of their numbers 0, 1, 2, 3... army[0](); // 10 from the shooter number 0 army[1](); // 10 from the shooter number 1 army[2](); // 10 ...and so on. Esto sucede porque i siempre es una referencia a la i externa dentro de la función makeArmy() .
Si ajustamos el código para que sea:
function makeArmy() { let shooters = []; let i = 0; while (i < 10) { // copy the varible i into the while lexical scope let j = i let shooter = function () { console.log(j); // that should show its number }; shooters.push(shooter); // and add it to the array i++; } // ...and return the array of shooters return shooters; } let army = makeArmy(); army[0](); // 0 army[1](); // 1 army[2](); // 2 El código anterior funciona como se esperaba porque en lugar de hacer referencia a la variable i dentro shooter() , la estamos copiando en j , por lo que está disponible para la función shooter en su propio ámbito.
Ahora, mi pregunta es, ¿por qué no funciona copiar la variable i dentro de la función? aunque efectivamente sigo copiando la variable? ¿Que me estoy perdiendo aqui?
Código:
function makeArmy() { let shooters = []; let i = 0; while (i < 10) { let shooter = function () { let j = i; console.log(j); // that should show its number }; shooters.push(shooter); // and add it to the array i++; } // ...and return the array of shooters return shooters; } let army = makeArmy(); // all shooters show 10 instead of their numbers 0, 1, 2, 3... army[0](); // 10 from the shooter number 0 army[1](); // 10 from the shooter number 1 army[2](); // 10 ...and so on.Porque estás copiando en un momento en el que ya i 10 .
De hecho, con let j = i en la función interna , no habrá diferencia en usar i directamente, porque esa asignación también se ejecuta solo cuando invocas esa función interna, y como se dijo, en este punto ya seré 10 , ya i la invocación ocurre mucho después de que se complete el bucle, por ejemplo, army[0]() .
Como notó, funciona si mueve let j = i fuera de la función interna (pero aún dentro del bucle). De esta manera, la asignación a la(s) variable(s) local(es) j ocurre en cada iteración inmediatamente, y la función interna luego se refiere a esas 10 j diferentes con sus valores correctos que se establecieron previamente en ese momento cuando i la respectiva valor que querías.
Por cierto, este problema no existirá si usa un bucle for porque for with let tiene algo de "magia" que crea un alcance semiseparado para cada iteración (la forma exacta en que funciona es un poco más complicada ) .
for (let i = 0; i < 10; i++) { let shooter = function () { console.log(i); }; shooters.push(shooter); }Cuando llama a console.log(i) en su función de tirador, el valor de i se refiere al que tiene una vez que finaliza el ciclo while, por lo tanto, sería el último valor que tenía. En su caso, el valor de i cambia con el tiempo, mostrando el último valor que tuvo. Cuando asigna eso a una variable ( let j = i ), copia ese valor y no la referencia, por lo que le da el resultado que desea.