【问题标题】:Binding listeners inside of a for loop : variable scope miscomprehension在 for 循环内绑定侦听器:变量范围误解
【发布时间】:2012-04-12 20:52:48
【问题描述】:

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

    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

谢谢!

【问题讨论】:

    标签: javascript jquery scope


    【解决方案1】:

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

    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
    【解决方案2】:

    这些 for 循环总是相同的(google it)。 JavaScript 没有块作用域而是函数作用域,因此当单击一个项目时,one 变量 selector 具有上次循环运行后的值(变量 item 相同)。

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

    【讨论】:

    • 感谢您的明确解释。我不知道这个函数级变量范围+1
    【解决方案3】:

    这个问题并不是严格意义上的变量范围。匿名函数在触发点击事件时运行,不是,当您在循环中定义它时。考虑以下与您的示例功能相同的内容:

    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”)。

    【讨论】:

    • 谢谢,但我怀疑在调用测试时会设置选择器。
    • 为什么不呢?这是一个全局变量。
    • 对不起,我认为这是一个函数......不知道为什么。你是对的。
    【解决方案4】:
    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.

    【讨论】:

      【解决方案5】:

      变量“选择器”和“项目”是对您存储值的位置的引用,当您单击其中一个 htl 元素时,这两个值的值是最后一个循环的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-12
        • 2017-11-22
        • 2011-05-27
        • 1970-01-01
        • 1970-01-01
        • 2018-08-17
        • 1970-01-01
        • 2019-12-04
        相关资源
        最近更新 更多