JavaScript回调函数中的变量范围

时间:2010-05-17 23:18:19

标签: javascript jquery

我希望下面的代码提醒“0”和“1”,但它会两次提醒“2”。我不明白原因。不知道这是不是jQuery的问题。另外,如果这些帖子不准确,请帮我编辑这篇文章的标题和标签。

<html>
    <head>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script type="text/javascript">
            $(function() {
                for (var i=0; i<2; i++) {
                    $.get('http://www.google.com/', function() {
                        alert(i);
                    });
                }
            });
        </script>
    </head>
    <body>
    </body>
</html>

5 个答案:

答案 0 :(得分:38)

您在所有回调中共享单个i变量。

由于Javascript闭包通过引用捕获变量,因此回调将始终使用当前值i。因此,当jQuery在循环执行后调用回调时,i将始终为2

您需要将i作为参数引用到单独的函数中。

例如:

function sendRequest(i) {
    $.get('http://www.google.com/', function() {
        alert(i);
    });
}

for (var i = 0; i < 2; i++) {
    sendRequest(i);
}

这样,每个回调都有一个单独的闭包,带有一个单独的i参数。

答案 1 :(得分:13)

替代SLaks的回答

$(function() {
    for (var i=0; i<2; i++) {
        $.get('http://www.google.com/', function(i) {
            return function() { alert(i); }
        }(i));
    }
});

答案 2 :(得分:1)

这里发生的是您的AJAX请求$.get在循环完成后正在完成。因此,i最终成为迭代完成时设置的最终变量,为2.这只是一个奇怪的JavaScript陷阱,与jQuery无关。

您可以做的一件事是异步排队这些调用,以便迭代停止,直到当前的AJAX请求完成。如果您不想这样做,则可以在每次迭代中捕获i闭包中的变量function

这样的事情:

for ( var i = 0; i < 2; i++ )
    (function(iter){
        $.get('http://www.google.com/', function(){
            alert( iter );
        });
    })(i); // Capture i

答案 3 :(得分:1)

另一种解决方案是接受你的回调并逐字地使它成为一个命名函数。

我为什么要这样做?
如果一个函数正在做一个变量需要占用新范围的东西,那么匿名函数很可能需要突破一个新函数。这还将确保不必通过复制变量或包装回调来为代码引入额外的复杂性。你的代码将保持简单和自我描述。

示例:

function getGoogleAndAlertIfSuccess(attemptNumber) {
    $.get('http://www.google.com/', function() {
        alert(attemptNumber);
    });
}

function testGoogle() {
    for (var i=0; i<2; i++) {
        getGoogleAndAlertIfSuccess(i);
    }
}

答案 4 :(得分:0)

您似乎已在循环中创建了一个闭包Mozilla开发人员参考有一个关于此的good section