2011-06-06 20 views
6

consideran este pequeño fragmento de JavaScript:¿Cómo puedo evitar los cierres de Javascript?

for(var i in map.maps) 
{ 
    buttons.push($("<button>").html(i).click(function() { alert(i); })); 
} 

Se crea un botón para cada uno de los campos del objeto map.maps (Es una matriz asociativa). Establecí el índice como el texto del botón y lo configuré para alertar también al índice. Obviamente, uno esperaría que todos los botones alertaran su propio texto cuando se hace clic, pero en su lugar todos los botones alertan al texto del índice final en el objeto map.maps al hacer clic.

Supongo que este comportamiento es causado por la forma clara en que JavaScript maneja los cierres, retrocede y ejecuta funciones desde los cierres en los que fueron creados.

La única forma en que me puedo imaginar para solucionar esto es establecer el índice como datos en el objeto de botón y usarlo desde la devolución de llamada de clic. También podría imitar los índices map.maps en mi objeto buttons y encontrar el índice correcto al hacer clic usando indexOf, pero prefiero el anterior.

Lo que estoy buscando en las respuestas es la confirmación de que lo estoy haciendo de la manera correcta, o una sugerencia sobre cómo debo hacerlo.

+1

Duplicación casi exacta de [¿Cómo paso el valor (no la referencia) de una variable JS a una función?] (Http://stackoverflow.com/questions/2568966/how-do-i-pass-the -value-not-the-reference-of-a-js-variable-to-a-function) –

Respuesta

9

Abrazo los cierres, no trabajan alrededor de ellos.

for(var i in map.maps) 
{ 
    (function(i){ 
     buttons.push($("<button>").html(i).click(function() { alert(i); })); 
    })(i); 
} 

Necesitas envolver el código que utiliza su var i de modo que termina en un cierre separado y el valor se mantiene en un var/param local para que se cierre.

Usar una función separada como en la respuesta de un día solitario oculta este comportamiento de cierre un poco, pero a la vez es mucho más claro.

+0

Mi código es (muy ligeramente) más rápido, porque la función solo se crea una vez. El efecto es exactamente el mismo, sin embargo. – lonesomeday

4

Si pasa el valor de cambiar a otra función como un parámetro, el valor será bloqueado en:

function createButton(name) { 
    return $("<button>").html(name).click(function() { alert(name); }); 
} 

for (var i in map.maps) { 
    buttons.push(createButton(i)); 
} 
0

Ésta es la forma más elegante de hacer lo que estás tratando de hacer:

var buttons = myCharts.map(function(chart,i) { 
    return $("<button>").html(chart).click(function(event){ 
     alert(chart); 
    }); 
} 

You necesidad cierres de código de forma elegante en javascript, y no debe trabajar alrededor de ellos. O bien, no puedes hacer cosas como bucles anidados (sin terribles ataques). Cuando necesite un cierre, use un cierre. No tengas miedo de definir nuevas funciones dentro de las funciones.

1
for(var i in map.maps){ 
    (function(i){ 
     buttons.push($("<button>").html(i).click(function() { alert(i); })) 
    })(i); 
} 

La causa por la cual el cierre fracasó en su caso es que es el valor actualizado aún incluso después de la función está ligada, que es en este caso es el controlador de eventos. Esto debido al hecho de que el cierre solo recuerda las referencias a las variables y no el valor real cuando estaban vinculadas.

Con la función anónima ejecutada puede aplicar el valor correcto, esto se logra pasando i a la función anónima, por lo tanto, dentro del alcance de la función anónima i se define de nuevo.

Cuestiones relacionadas