请参阅:
for (var i in this.items) {
var item = this.items[i];
$("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
$("#showcasebutton_"+item.id).click(function() {
alert(item.id);
self.switchto(item.id);
});
}
问题是警报的item.id始终是数组中最后一项的id(this.items)。怎么解决?
答案 0 :(得分:40)
您遇到的问题是变量item
随每个循环而变化。当您稍后引用item
时,将使用它保留的最后一个值。您可以使用称为closure的技术(本质上是一个返回函数的函数)来快速调整变量的范围。
for (var i in this.items) {
var item = this.items[i];
$("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
$("#showcasebutton_"+item.id).click(
// create an anonymous function that will scope "item"
(function(item) {
// that returns our function
return function() {
alert(item.id);
self.switchto(item.id);
};
})(item) // immediately call it with "item"
);
}
附注 - 我看到你在这里有jQuery。它有一个可以与数组一起使用的辅助函数$.each()
,可以作为简单for / each循环的快捷方式。由于作用域在此调用中的工作方式 - 您不需要使用闭包,因为“item”在调用时已经是函数的参数,而不是存储在父函数范围内的var
中,如在你的例子中是真的。
$.each(this.items,function(i, item) {
$("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
$("#showcasebutton_"+item.id).click(function() {
alert(item.id);
self.switchto(item.id);
});
});
答案 1 :(得分:4)
另一种方法是确保通过调用函数有效地完成= items[i]
业务。简而言之,这是:
for (var i in this.items) {
(function(item) {
$("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
$("#showcasebutton_"+item.id).click(function() {
alert(item.id);
self.switchto(item.id);
});
})(this.items[i]);
}
匿名函数有点乱,因此为了这个目的而让一个不那么匿名的函数变得更加可取,但它确实可以解决问题。
答案 2 :(得分:1)
Javascript闭包存储对其变量的引用,因此所有onclick处理程序都使用相同的变量。
您需要在中间函数中捕获变量,如下所示:
function buildClickHandler(pageNumber) {
return function() { //Create and return a new function
alert(item.id);
self.switchto(item.id);
}
}
然后,使用该函数创建click
处理程序,如下所示:
for (var i in this.items) {
var item = this.items[i];
$("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
$("#showcasebutton_"+item.id).click(buildClickHandler(item));
}
每次调用buildClickHandler
都会创建一个单独的闭包,它有自己的变量。
答案 3 :(得分:0)
试试这个循环
for (var i=0; i < this.items.length; i++) {
this.items[i]
};
答案 4 :(得分:0)
我非常清楚这是一个很老的帖子,但似乎设计jQuery的天才(我认为你必须使用它)已经为你的问题提供了最佳解决方案,正如我所理解的那样。
在库的新1.4版本they have added the jQuery.proxy() function中。这使您能够有效地修改您正在调用的函数的上下文/范围 - 完成jQuery方式,这可以确保您可以停止使用可能会弄乱事物的技术。