JavaScript变量作用域和事件处理程序

时间:2013-07-16 07:37:41

标签: javascript javascript-events event-handling scope

请看jsfiddle: http://jsfiddle.net/LsNCa/2/

function MyFunc() {

    for (var i = 0; i < 2; i++) { // i= 0, 1
        var myDiv = $('<div>');

        myDiv.click(function(e) {
            alert(i);    // both the two divs alert "2", not 0 and 1 as I expected
        });
        $('body').append(myDiv);
    }
}

var myFunc = new MyFunc();

当我点击它时,我希望div分别提醒“0”和“1”。但他们两个都警告“2”。

当我点击div并触发事件时,处理程序如何以及在何处找到变量i的值?

我知道添加一个闭包可以实现我的目标。但为什么呢?

4 个答案:

答案 0 :(得分:7)

    function MyFunc() {

    for (var i = 0; i < 2; i++) { // i= 0, 1
        (function(j) {
            var myDiv = $('<div>');

            myDiv.click(function(e) {
                alert(j);
            });
            $('body').append(myDiv);
        })(i);
    }
}

var myFunc = new MyFunc();

上面的代码是你如何使它正常工作。没有闭包,你总是i的最后一个值。我们所做的是将i发布到闭包中,让运行时“记住”那个时刻的值。

答案 1 :(得分:2)

您需要一个闭包,因为所有事件处理函数都引用相同的变量ifor循环更新此循环,当循环完成时,变量包含2。然后当有人点击其中一个DIV时,它会访问该变量。

要解决这个问题,每个事件处理程序都需要是一个带有自己的变量i的闭包,它包含创建闭包时值的快照。

答案 2 :(得分:1)

我建议您阅读this article

  

JavaScript提升声明。这意味着两个var语句   和函数声明将移动到其封闭的顶部   范围。

正如@Barmar在上面的回答中所说,变量i被两个事件处理程序引用。

您应该避免在循环内声明函数。下面有一些代码可以满足您的需求。

我假设您正在使用jQuery。

function MyFunc() {

    for (var i = 0; i < 2; i++) { // i= 0, 1
        var myDiv = $('<div>');

        $('body').append(myDiv);
    }
    $('div').on('click', function() {
        alert($(this).index());
    });
}

var myFunc = new MyFunc();

答案 3 :(得分:0)

在for循环完成后发生“alert()”调用,这意味着“i”的值将是之后任何内容的最后一个值。为了捕获“i”的单个值,您必须通过创建新函数为每个值创建一个闭包:

function MyFunc() {

    function alertFn(val) {
        return function () {
            alert(val);
        };
    }

    for (var i = 0; i < 2; i++) {
        var myDiv = $('<div>');
        myDiv.click(alertFn(i));
        $('body').append(myDiv);
    }
}

var myFunc = new MyFunc();

闭包在传递给函数时捕获“i”的值,允许alert()显示你期望的值。