Debido a que la variable original todavía se crea una instancia, si cambia el valor de esa variable cualquier lugar en el código, cuando la función se ejecuta después se tendrá el valor cambiado actual, no el valor cuando la función era la primera creado.
Antes de tratar de hacer el trabajo correcto cierre, tenga en cuenta que la declaración de la variable title
en repetidas ocasiones en el circuito no funciona (de hecho, se puede pensar de la variable siendo esencialmente izada en el function
's alcance- -a diferencia de algunos otros lenguajes, los bucles for
en JavaScript no tienen ámbito, por lo tanto, la variable se declara solo una vez para la función y es no declarada o redeclarada dentro del bucle). Declarar la variable fuera del ciclo debería ayudar a aclararle por qué su código no funciona como era de esperar.
Como es, cuando las devoluciones de llamada se ejecutan, porque tienen un cierre sobre la misma variable i
, todos ellos son afectados cuando i
incrementos y que todos ellos utilizar la corriente valor de i
cuando se ejecutan (que será mal como descubrió, debido a que las devoluciones de llamada ejecutan después de, el ciclo ha terminado de crear las devoluciones de llamada).El código asíncrono (como la respuesta de llamada JSON) no se ejecuta y no se puede ejecutar hasta que todo el código síncrono termina de ejecutarse, por lo que se garantiza que el ciclo se completará antes de que se ejecute alguna vez la devolución de llamada.
Para evitar esto se necesita una nueva función a ejecutar que tiene su propia alcance para que en las devoluciones de llamada declaradas dentro del bucle, hay un nuevo cierre sobre cada valor diferente . Puede hacerlo con una función separada, o simplemente usar una función anónima invocada en el parámetro de devolución de llamada. He aquí un ejemplo:
var title, i;
for (i = 0; i < some_array.length; i += 1) {
title = some_array[i];
$.getJSON(
'some.url/' + title,
(function(thisi) {
return function(data) {
do_something_with_data(data, thisi);
// Break the closure over `i` via the parameter `thisi`,
// which will hold the correct value from *invocation* time.
};
}(i)) // calling the function with the current value
);
}
Para mayor claridad voy a romperlo a cabo en una función separada para que pueda ver lo que está pasando:
function createCallback(item) {
return function(data) {
do_something_with_data(data, item);
// This reference to the `item` parameter does create a closure on it.
// However, its scope means that no caller function can change its value.
// Thus, since we don't change `item` anywhere inside `createCallback`, it
// will have the value as it was at the time the createCallback function
// was invoked.
};
}
var title, i, l = some_array.length;
for (i = 0; i < l; i += 1) {
title = some_array[i];
$.getJSON('some.url/' + title, createCallback(i));
// Note how this parameter is not a *reference* to the createCallback function,
// but the *value that createCallback() returns*, which is itself a function.
}
Nota: desde la matriz al parecer sólo tiene títulos en el mismo, podría considerar usar la variable title
en lugar de i
, que requiere que regrese a some_array
. Pero de cualquier manera funciona, sabes lo que quieres.
Una forma potencialmente útil para pensar en esto que la función de devolución de llamada de creación (ya sea el anónimo uno o el createCallback
uno) en esencia convierte el valor de la variable de i
en thisi
variables separadas, a través de cada vez que la introducción de un nuevo funcionar con su propio alcance Quizás podría decirse que "los parámetros rompen los valores de los cierres".
Solo tenga cuidado: esta técnica no funcionará en los objetos sin copiarlos, ya que los objetos son tipos de referencia. Pasarlos simplemente como parámetros no arrojará algo que no pueda cambiarse después de los hechos. Puede duplicar la dirección de una calle todo lo que quiera, pero esto no crea una nueva casa. Debes construir una nueva casa si quieres una dirección que conduzca a algo diferente.
+1 Excepto @Chris quiere mantener una referencia a cada 'i'. – Jeremy
D'oh, gracias, me lo perdí. Se agregó en. – patorjk
Intenté adaptar esto, pero ¿dónde ** datos ** obtiene su valor ahora? No está definido para mí ahora. – Chris