Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I expected the code below to alert "0" and "1", but it alert "2" twice. I don't the reason. Don't know if it is a problem of jQuery. Also, please help me to edit title and tags of this post if they are inaccurate.

<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>
share|improve this question
9  
Wow this problem is so common. We need to put a static answer on the front page. – ChaosPandion May 17 '10 at 23:20
2  
@chaos: Right beneath "Don't do HTML with regex", I guess. ;) – Tomalak May 17 '10 at 23:23
2  
(no offense) JavaScript Closures for Dummies Example 5 – Felix Kling May 17 '10 at 23:23
To be fair, the Closure Loop Problem is something that's arguably a language design flaw in JavaScript (and others that provide closures but still use C-style per-function scoping). – bobince May 17 '10 at 23:47

4 Answers

up vote 15 down vote accepted

You're sharing the single i variable among all of the callbacks.

Because Javascript closures capture variables by reference, the callbacks will always use the current value of i. Therefore, when jQuery calls the callbacks after the loop executes, i will always be 2.

You need to reference i as the parameter to a separate function.

For example:

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

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

This way, each callback will have a separate closure with a separate i parameter.

share|improve this answer
1  
The function level scoping makes this a must. – ChaosPandion May 17 '10 at 23:22

Alternative to SLaks' answer

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

It appears that you've created a closure inside your loop The Mozilla Developers Reference has a good section about this.

share|improve this answer

What's occurring here is your AJAX request $.get is completing after the loop has completed. Because of this, i ends up being the final variable it's set to when the iterations complete, being 2. This is just a weird JavaScript gotcha, and has nothing to do with jQuery.

One thing you can do is queue up these calls asynchronously so that iteration halts until the current AJAX request completes. If you don't want to do that, you can capture the variable i in a function closure in each iteration.

Something like this:

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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.