考虑到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)。
你的意思是document.getElementById(e.target.id).addEventListener(....... ??:S –
我的意思是alert(e.target.id) –
这不会影响代码的工作!警报只是显示值... –