2011-04-05 26 views
5

me gustaría hacer algo a lo largo del siguiente:Javascript: cierre del ciclo?

for(var i = 0; i < 10; ++i) { 
    createButton(x, y, function() { alert("button " + i + " pressed"); } 
} 

El con esto es que siempre me dan el valor final de i porque el cierre de Javasript no es por valor.
Entonces, ¿cómo puedo hacer esto con javascript?

+0

Puede editar createButton, permitiendo que se pase otro argumento, es decir, i. De esta forma puedes almacenar i en tu función createButton y usarla. – rsplak

+0

posible duplicado de [Javascript closure inside loops: ejemplo práctico simple] (http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – rds

Respuesta

6
for(var i = 0; i < 10; i++) { 
    (function(i) { 
     createButton(function() { alert("button " + i + " pressed"); }); 
    })(i); 
} 

Tenga en cuenta que JSLint no le gusta este patrón. Lanza "No hagas funciones dentro de un bucle".

Demostración en directo:http://jsfiddle.net/simevidas/ZKeXX/

+0

Me gusta esta respuesta más que la de Peter debido a su limpieza. Sería bueno si más navegadores soportaran la palabra clave 'let'. – McStretch

+0

@McStretch Intenté hacer una demostración 'let' en jsFiddle, pero no pude hacerlo funcionar. Mira aquí: http://jsfiddle.net/simevidas/ZKeXX/1/ Firefox 4 arroja un error. –

+0

@ Šime - Acabo de ver esta pregunta: http://stackoverflow.com/questions/2356830/what-browsers-currently-support-javascripts-let-keyword, que dice que tienes que decirle explícitamente al navegador (Firefox solo ahora mismo) que estás usando 1.7. Aquí hay un violín actualizado: http://jsfiddle.net/simevidas/ZKeXX/1/. Bastante cojo ¿eh? Obviamente no es realmente una buena solución hasta que todos apoyen 1.7 o más, y que sepan cuándo sucederá eso. – McStretch

1

Debe poner el cierre en una función separada.

for(var dontUse = 0; dontUse < 10; ++dontUse) { 
    (function(i) { 
     createButton(x, y, function() { alert("button " + i + " pressed"); } 
    })(dontUse); 
} 

Thise código crea una función anónima que se lleva a i como un parámetro para cada iteración del bucle.
Dado que esta función anónima tiene un parámetro i por separado para cada iteración, soluciona el problema.

Esto es equivalente a

function createIndexedButton(i) { 
    createButton(x, y, function() { alert("button " + i + " pressed"); } 
} 

for(var i = 0; i < 10; ++i) { 
    createIndexedButton(i); 
} 
0
for(var i = 0; i < 10; ++i) { 
    createButton(x, y, (function(n) { 
     return function() { 
      alert("button " + n + " pressed"); 
     } 
    }(i)); 
} 

La función anónima en el exterior se invoca automáticamente y se crea un nuevo cierre con n en su alcance, donde que toma el vigente en ese momento el valor de i cada Hora en que se invoca.

4

crear un nuevo ámbito para el cierre mediante la ejecución de otra función:

for(var i = 0; i < 10; ++i) { 
    createButton(x,y, function(value) { return function() { alert(...); }; }(i)); 
} 

http://www.mennovanslooten.nl/blog/post/62

+0

1.Es posible que desee colocar un punto y coma al final de la declaración de devolución para que el código sea un poco más legible. 2. Los IIFE generalmente están envueltos en parens. –

+0

@ Šime, sí, estoy de acuerdo. –

7

Una solución, si estás codifica para un navegador que utiliza JavaScript 1.7 o superior, es utilizar la palabra clave let:

for(var i = 0; i < 10; ++i) { 
    let index = i; 
    createButton(x, y, function() { alert("button " + index + " pressed"); } 
} 

Desde el MDC Doc Centro:

La palabra clave let ocasiona que la variable se cree con el bloque ámbito de nivel, lo que provoca que se cree una nueva referencia para cada iteración de el bucle for. Esto significa que se captura una variable separada para cada cierre de , resolviendo el problema causado por el entorno compartido.

Compruebe el MDC Doc Center para el enfoque tradicional (creando otro cierre).