从Javascriptclosures循环访问外部variables

看到:

for (var i in this.items) { var item = this.items[i]; $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"http://img.dovov.comshowcase/icon-"+item.id+".png\" /></li>"); $("#showcasebutton_"+item.id).click(function() { alert(item.id); self.switchto(item.id); }); } 

问题在于,惊动item.id始终是数组中最后一个项目的标识(this.items)。 如何解决?

您在这里遇到的问题是variablesitem随着每个循环而改变。 当您稍后引用item时,将使用它保存的最后一个值。 你可以使用一种称为闭包 (本质上是一个返回函数的函数)的技巧,以快速确定variables的范围。

  for (var i in this.items) { var item = this.items[i]; $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"http://img.dovov.comshowcase/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() ,可以和数组一起使用,并且可以作为简单的/每个循环的快捷方式。 由于在这个调用中作用域的工作方式 – 你不需要使用闭包,因为“item”已经是被调用的函数的参数,而不是存储在父函数作用域的var中,就像你的例。

 $.each(this.items,function(i, item) { $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"http://img.dovov.comshowcase/icon-"+item.id+".png\" /></li>"); $("#showcasebutton_"+item.id).click(function() { alert(item.id); self.switchto(item.id); }); }); 

另一种方法是通过调用函数来确保= items[i]业务是有效完成的。 简而言之,这个:

 for (var i in this.items) { (function(item) { $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"http://img.dovov.comshowcase/icon-"+item.id+".png\" /></li>"); $("#showcasebutton_"+item.id).click(function() { alert(item.id); self.switchto(item.id); }); })(this.items[i]); } 

这个匿名函数有点乱,所以最好有一个不太匿名的函数来达到目的,但它的确有用。

Javascriptclosures存储对其variables的引用,所以你所有的onclick处理程序都使用相同的variables。

您需要在中间函数中捕获variables,如下所示:

 function buildClickHandler(pageNumber) { return function() { //Create and return a new function alert(item.id); self.switchto(item.id); } } 

然后,使用该函数来创buildclick处理程序,如下所示:

 for (var i in this.items) { var item = this.items[i]; $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"http://img.dovov.comshowcase/icon-"+item.id+".png\" /></li>"); $("#showcasebutton_"+item.id).click(buildClickHandler(item)); } 

每次调用buildClickHandler都会创build一个具有自己的variables的单独的闭包。

尝试这个循环

 for (var i=0; i < this.items.length; i++) { this.items[i] }; 

我非常清楚这是一个旧的post,但是据我所知,devisejQuery(我认为你必须使用的)的人们似乎已经为你的问题提供了最优化的解决scheme。

在新的1.4版本库中, 他们添加了jQuery.proxy()函数 。 这使您可以有效地修改您调用的函数的上下文/作用域 – 完成jQuery方式,这可以确保您可以停止使用可能会弄乱事情的技术。