2010-03-26 20 views
9

estoy tratando de hacer lo siguiente:La variable en las funciones de devolución de llamada de JavaScript siempre obtiene el último valor en el ciclo?

Tengo un conjunto de imágenes y seleccionar (desplegables) elementos HTML, 30 de cada uno. Estoy tratando de usar AddEventListener en un bucle del 1 al 30, de modo que cuando cambio el valor de la selección, la imagen src se actualice (y la imagen cambie).

La función AddEventListener es éste:

function AddEventListener(element, eventType, handler, capture) 
{ 
    if (element.addEventListener) 
     element.addEventListener(eventType, handler, capture); 
    else if (element.attachEvent) 
     element.attachEvent("on" + eventType, handler); 
} 

yo probamos este y funcionó:

var urlfolderanimalimages = "http://localhost/animalimages/"; 
var testselect = "sel15"; 
var testimg = "i15"; 

AddEventListener(document.getElementById(testselect), "change", function(e) { 
    document.getElementById(testimg).src = urlfolderanimalimages + document.getElementById(testselect).value; 
    document.getElementById(testimg).style.display = 'inline'; 

    if (e.preventDefault) e.preventDefault(); 
    else e.returnResult = false; 
    if (e.stopPropagation) e.stopPropagation(); 
    else e.cancelBubble = true; 
}, false); 

Pero luego trató de llamarlo en un bucle y no funciona. El evento se agrega, pero cuando cambio cualquier selección, actualizará la última (la imagen con id i30).

var urlfolderanimalimages = "http://localhost/animalimages/"; 

for (k=1;k<=30;k++) { 
    var idselect = "sel" + k; 
    var idimage = "i" + k; 

    AddEventListener(document.getElementById(idselect), "change", function(e) { 
     document.getElementById(idimage).src = urlfolderanimalimages + document.getElementById(idselect).value; 
     document.getElementById(idimage).style.display = 'inline'; 

     if (e.preventDefault) e.preventDefault(); 
     else e.returnResult = false; 
     if (e.stopPropagation) e.stopPropagation(); 
     else e.cancelBubble = true; 
    }, false); 

} 

¿Qué estoy haciendo mal? Soy nuevo en JavaScript (y la programación en general), lo siento por el código que inducen el vómito :(

Respuesta

8

El problema es que son 'cierre' sobre la misma variable .

hace var no declarar una variable . simplemente anota un 'dejar de mirar hacia arriba' para un identificador dentro de un contexto de ejecución definido.

por favor, vea Javascript Closures "FAQ Notes" para todos los detalles bonitos. las secciones sobre 'contexto de ejecución' y ' cadena de alcance 'son los más interesantes.

El idioma común es realizar una doble vinculación para crear un nuevo contexto de ejecución.

E.g.

var k 
for (k = 1; k < 10; k++) { 
    setTimeout((function (_k) { 
    return function() { 
     alert(_k) 
    } 
    })(k), k * 100) 
} 

A partir de JavaScript 5ª Edición existe Function.bind (que también se puede implementar en 3ª edición como bind from prototype.js), que puede ser utilizado como tal:

var k 
for (k = 1; k < 10; k++) { 
    setTimeout((function() { 
    alert(this) 
    }).bind(k), k * 100) 
} 

Este constructo es al que se hace referencia como Declaración de Variables en la especificación ECMAScript. Sin embargo, se enfatiza esta afirmación, por engañosa que pueda ser vista, para traer a casa un punto: vea también "elevación variable".

+0

Muchas gracias, pst. Honestamente soy muy nuevo en esto, así que no entendí lo de anoche (aunque era muy tarde y estaba muy cansado, así que eso podría haber contribuido a ello: p). Le daré otra lectura hoy y veré si puedo hacer que funcione. ¡Gracias de nuevo! :) –

1

También encontré esta solución a http://meshfields.de/event-listeners-for-loop/:

var myArr = [0,1,2,3]; 

for (var i = 0; i < myArr.length; i+=1) { 

(function (i) { 

    document.getElementById('myDOMelement' myArr[i]).onclick = function() { 

     if (window.console.firebug !== undefined) { 
      console.log('myDOMelement' myArr[i]); 
     } 
     else { 
       alert('myDOMelement' myArr[i]); 
     } 
     }; 
    }) (i); 
} 
Cuestiones relacionadas