在for循环中绑定侦听器:变量范围误解

我有一个变量范围问题,我不明白为什么会发生这种情况以及如何摆脱它:

var items = ['foo', 'bar']; for (var index in items) { var item = items[index]; var selector = '.'+item+'-class'; $(selector).bind('click', function() { console.log("class: "+$(this).attr('class')); console.log("selector: "+selector); console.log("item: "+item); }); } 

考虑到此代码通过以下HTML执行:

 
Foo
Bar

单击“Foo”会在第一行中回显正确的类(即“foo-class”),但选择器和后面的项目名称与bar相关。 我认为问题在于循环的第二次迭代重置了第一次使用的变量。

我认为循环内部的声明应该清楚地声明它们在这个级别的范围。 我错了吗 ? 为什么? 我该如何解决?

我不是在寻找一种解决方法,我想要一些干净的东西,更好地理解javascript变量范围机制。

这里是jsfiddle 。

谢谢 !

这是你的小提琴示例更新。

 var items = ['foo', 'bar']; for (var index in items) { (function() { var item = items[index]; var selector = '.' + item + '-class'; $(selector).bind('click', function() { console.log("class: " + $(this).attr('class')); console.log("selector: " + selector); console.log("item: " + item); }); })(); }​ 

创建匿名函数将为每个已定义的变量定义新范围

提示:尝试创建一个单独的函数来执行绑定,只是为了保持代码更清晰。

这些for循环(google)总是一样的。 JavaScript没有块范围,但是没有函数范围,所以当单击一个项时, 一个变量selector具有它在最后一个循环运行后具有的值(对于变量item )。

要解决这个问题,你需要在循环中使用另一个闭包,它将变量存储在自己的作用域中。 这意味着您需要为每个循环运行执行一个函数。

问题并不严格关于可变范围。 匿名函数在触发click事件时运行, 而不是在循环中定义时运行。 请考虑以下function与您的示例相同:

 var items = ['foo', 'bar']; for (var index in items) { var item = items[index]; var selector = '.'+item+'-class'; $(selector).bind( 'click', test ); }​ function test() { console.log("selector: "+selector); }  var items = ['foo', 'bar']; for (var index in items) { var item = items[index]; var selector = '.'+item+'-class'; $(selector).bind( 'click', test ); }​ function test() { console.log("selector: "+selector); } 

这(希望)演示了正在发生的事情:函数中的全局变量selector在调用函数时在两种情况下都是相同的(“bar”)。

 var items = ['foo', 'bar']; for (var index in items) { (function(i){ var item = items[i]; var selector = '.'+item+'-class'; $(selector).bind('click', function() { console.log("class: "+$(this).attr('class')); console.log("selector: "+selector); console.log("item: "+item); }); })(index); } 

在这里小提琴。

Vars“selector”和“item”是对存储值的位置的引用,当您单击其中一个htl元素时,这两个值的值是最后一个循环的一个。