JavaScript:在循环中添加事件 - 闭包问题

时间:2013-10-18 06:41:30

标签: javascript closures

我想在for循环中向li添加事件。

我知道什么总是出错:闭包可以访问的ii的最后一个值。 i需要锁定在关闭中。

要解决此问题,请立即使用调用函数表达式。

我不明白为什么这不起作用!

for (var i = 0; i < 10; i++){
    var li = document.createElement('li');
    ul.appendChild(li);
    li.onclick = (function(i2){
        return slideTo(i2);    // slideTo is a global function
    }(i));

但我知道这会奏效:

li.onclick = (function(i2){
    return function(){ 
        slideTo(i2);        // slideTo is a global function
    }
}(i));

为什么我需要将slideTo(i)放入匿名函数???

这两个表达式之间的区别是什么?

非常感谢!!!

2 个答案:

答案 0 :(得分:0)

在第一种情况下,您只需将slideTo(i2)的值分配给onclick

li.onclick = (function(i2){
    // Here, "i2" is **immediately** used to invoke
    // slideTo(i2). It is invoked right here, in 
    // every loop iteration. 
    return slideTo(i2);
}(i));

以上将在每次循环迭代中进行评估,因此它等同于:

li.onclick = slideTo(i);

在合同中,在第二个示例中,您创建了一个正确的闭包,从而将{strong>函数(不是第一个场景中的)分配给li.onclick侦听器:< / p>

li.onclick = (function(i2){
    // Here, "i2" is in a scope, but it's **not immediately** used.
    // Instead, you are returning function which will be assigned
    // to "li.onclick" but with THIS scope (i.e. scope with
    // "i2" value).
    //
    // New scope is created in every loop iteration, but the following
    // function **is not called** in a loop.
    return function() {
         // Later, when <li> is clicked, slideTo(i2) will be called.
         slideTo(i2);
    }
}(i));

答案 1 :(得分:0)

第二种形式是创建变量绑定所必需的(即i2) - 第一种形式是立即评估(它不会返回函数对象,它执行后面的工作),因此不是“回调”。

请记住仅新功能范围创建新变量。如果没有双闭包,您将引用相同的 i变量。另一种方法是使用Function.bind(它本身可以用闭包模拟)。