JavaScript 回调函数中的变量范围
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2853601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
scope of variables in JavaScript callback functions
提问by Ethan
I expected the code below to alert "0" and "1", but it alert "2" twice. I don't understand 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.
我希望下面的代码警告“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>
回答by SLaks
You're sharing the single ivariable among all of the callbacks.
您i在所有回调之间共享单个变量。
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, iwill always be 2.
由于 Javascript 闭包通过引用捕获变量,因此回调将始终使用 的当前值i。因此,当 jQuery 在循环执行后调用回调时,i将始终为2.
You need to reference ias the parameter to a separate function.
您需要i作为参数引用一个单独的函数。
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 iparameter.
这样,每个回调将有一个单独的闭包和一个单独的i参数。
回答by Tomalak
Alternative to SLaks' answer
替代 SLaks 的答案
$(function() {
for (var i=0; i<2; i++) {
$.get('http://www.google.com/', function(i) {
return function() { alert(i); }
}(i));
}
});
回答by Leigh McCulloch
An alternative solution to this is to take your callback and literally make it a named function.
对此的另一种解决方案是获取您的回调并使其成为命名函数。
Why would I want to do this?
If a function is doing something where a variable needs to take new scope then it's likely the anonymous function warrants breaking out into a new function. This will also ensure that extra complexity is not introduced to your code by having to copy variables or wrap callbacks. You're code will remain simple and self descriptive.
我为什么要这样做?
如果一个函数正在做一些变量需要采用新作用域的事情,那么匿名函数很可能需要突破到一个新函数中。这也将确保不会因为必须复制变量或包装回调而将额外的复杂性引入到您的代码中。您的代码将保持简单和自我描述。
Example:
例子:
function getGoogleAndAlertIfSuccess(attemptNumber) {
$.get('http://www.google.com/', function() {
alert(attemptNumber);
});
}
function testGoogle() {
for (var i=0; i<2; i++) {
getGoogleAndAlertIfSuccess(i);
}
}
回答by ground5hark
What's occurring here is your AJAX request $.getis completing after the loop has completed. Because of this, iends 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.
这里发生的是$.get循环完成后您的 AJAX 请求正在完成。因此,i最终成为迭代完成时设置的最终变量,为 2。这只是一个奇怪的 JavaScript 问题,与 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 iin a functionclosure in each iteration.
您可以做的一件事是异步排队这些调用,以便迭代停止,直到当前的 AJAX 请求完成。如果您不想这样做,您可以在每次迭代i的function闭包中捕获变量。
Something like this:
像这样的东西:
for ( var i = 0; i < 2; i++ )
(function(iter){
$.get('http://www.google.com/', function(){
alert( iter );
});
})(i); // Capture i
回答by BradBrening
It appears that you've created a closure inside your loop The Mozilla Developers Reference has a good sectionabout this.
您似乎在循环中创建了一个闭包 Mozilla 开发人员参考对此有一个很好的部分。

