-1

我有几个pieChart对象存储在shapes数组中...我想为每个对象添加事件侦听器。我试图做这样的:循环内的EventListeners [JavaScript]

var tempS = shapes.slice(); 

for(var i=0; i<shapes.length; i++) 
{ 
    var S = tempS.pop(); 
    if(S.name == 'pieChart') 
    { 
     document.getElementById(S.id).addEventListener('mousedown', function(e){ 
      alert(S.id); 
    }, false); 
} 

}

这里的问题是,即使当我点击pieChart2(ID-> 2),它总是给ID-> 1(因为它最后弹出)。请解释这种行为,以及可能是这种做法的有效方式。

回答

0

考虑到var声明具有的功能范围(或全球性的,如果在全球范围内声明的),你的代码是相当于:

var tempS = shapes.slice(), 
    i, S; 

for (i = 0; i < shapes.length; i++) { 
    S = tempS.pop(); 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); 
     }, false); 
    } 
} 

现在很明显S的范围在for块之外,并且由于事件处理程序将在循环完成后触发,所以S将具有最后一次迭代的值。

您需要通过回调工厂(如此related answer)或IIFE来创建新范围,以捕获迭代的当前值S

var tempS = shapes.slice(); 

for (var i = 0; i < shapes.length; i++) { (function() {//introduces a new scope 
    var S = tempS.pop(); //now S is scoped inside this iteration's IIFE 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); //will reference the IIFE scope's S 
     }, false); 
    } 
}()); } 

您可以在许多替代的方式做到这一点为好,例如,使用Array#forEach

var tempS = shapes.slice(); 
shapes.forEach(function(S) { //S is now scoped in the forEach callback scope 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); 
     }, false); 
    } 
}); 

注意,这将改变迭代顺序,但我相信它不会为这件事用例。


在ES6将有可能使用let创建块作用域的变量:

for (var i = 0; i < shapes.length; i++) { 
    let S = tempS.pop(); //scoped inside the `for` block 
    if (S.name == 'pieChart') { 
     document.getElementById(S.id).addEventListener('mousedown', function (e) { 
      alert(S.id); 
     }, false); 
    } 
} 

我在这里留下这种方法对于未来的读者,为let尚未准备好生产呢。尽管最近的浏览器确实有实验性实现(请参阅ES6 compat table)。

0

您可以使用

e.target.id 

代替

S.id 

在事件监听器

+0

你的意思是document.getElementById(e.target.id).addEventListener(....... ??:S –

+0

我的意思是alert(e.target.id) –

+0

这不会影响代码的工作!警报只是显示值... –

1

here

使用underscore.js:

_.each(shapes, function(s) { 
    if(s.name === 'pieChart') { 
     document.getElementById(s.id).addEventListener('mousedown',function(e) { 
      e = e || window.event; 
      var target = e.target || e.srcElement; 
      alert(target.id); 
     }); 
    } 
}); 

来解释你的代码的行为,你要记住,JavaScript使用功能范围,而不是封锁范围。因此,由于您的定义S在eventListener回调函数之外,回调中的S对引用的引用将是S的当前值,循环执行后这些值将是shapes数组中的最后一个pieChart对象。

1

在回调函数中,使用this而不是再次访问id