在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
单击“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元素时,这两个值的值是最后一个循环的一个。