从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方式,这可以确保您可以停止使用可能会弄乱事情的技术。