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

时间:2012-04-12 20:52:48

标签: javascript jquery scope

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

    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执行:

<div class="foo-class">Foo</div>
<div class="bar-class">Bar</div>

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

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

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

这里是jsfiddle

谢谢!

5 个答案:

答案 0 :(得分:4)

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

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);
        });
    })();
}​

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

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

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在调用函数时在两种情况下都相同(&#34; bar&#34 ;)

答案 3 :(得分:0)

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);
}

Fiddle here.

答案 4 :(得分:0)

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