我试图在onclick事件处理函数中获取一个对象。
但它没有像我期望的那样发挥作用。
例如,如果我运行此代码:
var entries = [{id: 1},{id: 2},{id: 3}];
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
document.getElementById(entry.id).onclick = function () {
console.log("this.id: " + this.id);
console.log("entry.id: " + entry.id);
};
}
我的期望是:
this.id: 1
entry.id: 1
this.id: 2
entry.id: 2
this.id: 3
entry.id: 3
但我得到的是:
this.id: 1
entry.id: 3
this.id: 2
entry.id: 3
this.id: 3
entry.id: 3
为什么条目对象始终是id为3的条目?
如何在click事件处理程序中获取正确的条目对象?
答案 0 :(得分:6)
解决此问题的一种方法是:
var entries = [{id: 1},{id: 2},{id: 3}];
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
document.getElementById(entry.id).onclick = (function (id) {
return function () {
console.log("this.id: " + this.id);
console.log("entry.id: " + id);
};
})(entry.id);
}
您可以使用自执行函数(其目的是提供entry.id将绑定的闭包)来返回绑定到特定id的新onclick处理程序。
如果你不这样做,你所有的onclick处理程序都绑定到同一个条目变量,并以for循环中收到的最后一个值结束。
答案 1 :(得分:2)
这是关闭的棘手问题之一。您正在使用entry
的闭包创建这些事件处理程序。他们都可以访问该变量,即确切的变量。因此,一旦这些事件触发,它们只会获得设置为最后一个值。你需要打破关闭。这是一种方式。
function addClickHandlers() {
var entries = [{id: 1},{id: 2},{id: 3}];
var i = entries.length;
while (i--) {
var entry = entries[i];
document.getElementById(entry.id).onclick = getClickHandler(entry);
}
}
function getClickHandler(entry) {
return function() {
console.log("this.id: " + this.id);
console.log("entry.id: " + entry.id);
};
}
注意:我将for循环更改为一段时间只是因为当订单不重要时,这是在javascript中循环的最快方式,我认为它很光滑。
还有一些其他方法可以解决这种情况。我发现我一直都在使用它们。
在Ext中有createDelegate
myhandler.createDelegate(scope, [arguments], [appendArgs]);
对于javascript 1.8.5,有Function.prototype.bind
myhandler.bind(scope, arguments)
编写Function.prototype.bind非常简单(lifted from here)
Function.prototype.bind = function(self, var_args) {
var thisFunc = this;
var leftArgs = Array.slice(arguments, 1);
return function(var_args) {
var args = leftArgs.concat(Array.slice(arguments, 0));
return thisFunc.apply(self, args);
};
};
答案 2 :(得分:2)
这是因为闭包在JavaScript中的工作方式。所有3个元素的onclick引用存储相同的函数,该函数在循环后具有指向最后一个条目的条目。因此结果。您可以通过将其包装到具有所需条目的另一个函数中来获得结果。以下是一种方法:
var entries = [{id: 1},{id: 2},{id: 3}];
for (var i = 0; i < entries.length; i++) {
var entry = entries[i];
function setOnClickHandler(entry) {
document.getElementById(entry.id).onclick = function () {
console.log("this.id: " + this.id);
console.log("entry.id: " + entry.id);
};
}
setOnClickHandler(entry);
}
我在this上写了一篇小帖子。