嵌套函数中的变量值在定义时而不是在调用时评估

时间:2013-08-30 13:09:47

标签: javascript closures

考虑以下代码:

for( var i = 1; i <= 2; ++i )
{
 $( '#id' + i ).click(
   function()
   {
     alert( 'ID = ' + i );
   }
  )
}

问题是,当点击id1或id2时,警报总是说ID = 3.现在我知道为什么会发生这种情况(在通话时评估),我只是好奇是否有办法防止这种情况发生? (1)

这里的许多问题和文章一般都很好地解释了闭包的概念,但是我无法找到任何避免它的技术。

在旁注中,我尝试使用(注意额外的关键字“new”):

new function() { alert( 'ID = ' + i ) }

然而,它在定义时直接调用警报,并且对点击事件不执行任何操作。有什么想法吗? (2)

3 个答案:

答案 0 :(得分:2)

一种方式就是这样。

HTML

<div id="id1">ID1</div>
<div id="id2">ID2</div>
<div id="id3">ID3</div>

的Javascript

for (var i = 1; i <= 2; i += 1) {
    (function (j) {
        $('#id' + j).click(

        function () {
            alert('ID = ' + j);
        });
    }(i));
}

jsfiddle

答案 1 :(得分:1)

基本上,您需要创建一个新的范围,i的值不会改变。因此,为了说明,您可以在循环外创建函数,传递当前值:

function createClickAction(i){
    return function(){
        alert( 'ID = ' + i );
    }
}

for(var i = 1;i <= 2; ++i){
    $( '#id' + i ).click(
        createClickAction(i)
    );
}

但是,执行相同操作的更简单方法是将值传递给IIFE

for(var i = 1;i <= 2; ++i){
    (function(i){
        $( '#id' + i ).click(
            function(){
                alert( 'ID = ' + i );
            }
        );
    })(i);
}

以下是有关语法new function(){...}的一些讨论 它具有与IIFE相同的效果,因为您实例化一个自治函数,作为构造函数。所以就像说:

function Message(){
    alert('hi');
}
new Message();

......但没有命名。
并传递参数:

new function(msg){
    alert(msg)   
}('hi');

所以你可能很接近找到这个解决方案:

for(var i = 1;i <= 2; ++i){
    new function(i){
        $( '#id' + i ).click(
            function(){
                alert( 'ID = ' + i );
            }
        );
    }(i);
}

答案 2 :(得分:0)

怎么样 -

for( var i = 1; i <= 2; ++i )
{
 $( '#id' + i ).click(
   function()
   {
     alert( 'ID = ' + this.id.substring('#id'.length) );
   }
  )
}