Controladores de eventos dentro de un bucle de Javascript: ¿necesitan un cierre?

Resuelto matt b asked hace 16 años • 2 respuestas

Estoy trabajando con un poco de código HTML y Javascript que tomé de otra persona. La página recarga una tabla de datos (mediante una solicitud asincrónica) cada diez segundos y luego reconstruye la tabla usando algún código DOM. El código en cuestión se parece a esto:

var blah = xmlres.getElementsByTagName('blah');
for(var i = 0; i < blah.length; i++) {
    var td = document.createElement('td');
    var select = document.createElement('select');
    select.setAttribute("...", "...");
    select.onchange = function() {
        onStatusChanged(select, callid, anotherid);
    };
    td.appendChild(select);
}

Sin embargo, cuando onchangese activa el evento para un <select>elemento, parece que se pasan los mismos valores al onStatusChanged()método para cada uno <select>en la tabla (lo he verificado en cada iteración del bucle callidy anotheridse me están dando valores nuevos y distintos).

Sospecho que esto ocurre debido a la naturaleza de cómo configuro el controlador de eventos, con la select.onchange = function()sintaxis. Si entiendo cómo funciona esto correctamente, esta sintaxis establece un cierre para que el evento onchange sea una función que se refiere a estas dos referencias, que terminan teniendo un valor final de lo que sea que estén configurados en la última iteración del ciclo. Cuando se activa el evento, el valor al que hace referencia callidy anotherides el valor establecido en la última iteración, no el valor establecido en la iteración individual.

¿Hay alguna manera de copiar el valor de los parámetros a los que estoy pasando onStatusChanged()?

Cambié el título para reflejar mejor la pregunta y la respuesta aceptada.

matt b avatar Dec 05 '08 02:12 matt b
Aceptado

De hecho, es necesario implementar un cierre aquí. Esto debería funcionar (avíseme, no lo probé)

var blah = xmlres.getElementsByTagName('blah');
for(var i = 0; i < blah.length; i++) {
    var td = document.createElement('td');
    var select = document.createElement('select');
    select.setAttribute("...", "...");
    select.onchange = function(s,c,a)
    {
        return function()
        {
            onStatusChanged(s,c,a);
        }
    }(select, callid, anotherid);
    td.appendChild(select);
}
Peter Bailey avatar Dec 04 '2008 19:12 Peter Bailey