考慮到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) –
這不會影響代碼的工作!警報只是顯示值... –