8

请参阅 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

4 回答 4

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 发布到闭包中,并让运行时“记住”那一刻的价值。

于 2013-07-16T07:46:29.153 回答
2

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

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

于 2013-07-16T07:42:00.410 回答
1

我建议你阅读这篇文章

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();
于 2013-07-16T07:51:47.203 回答
0

"alert()" 调用发生在 for 循环完成之后,这意味着 "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() 显示您期望的值。

于 2013-07-16T07:53:11.717 回答