我在Google上搜索与海报类似的问题时,发现了一个帖子(https://bbs.archlinux.org/viewtopic.php?id=58640)。
他试图找出下面代码的修复方法。
for(var i=0; i<3; i++) {
req[i] = new XMLHttpRequest();
req[i].onreadystatechange = function() {
if(req[i].readyState == 4 && req[i].status == 200) {
URL = url[i];
success();
}
}
req[i].open("GET", url[i], true);
req[i].send(null);
}
解决方案是
for(var i=0; i<3; i++) {
req[i] = new XMLHttpRequest();
req[i].onreadystatechange = function(index) {
return function() {
if(req[index].readyState == 4 && req[index].status == 200) {
URL = url[index];
success();
}
};
}(i);
req[i].open("GET", url[i], true);
req[i].send(null);
}
这是因为req[i]
的范围问题。
我在i
内部使用类似函数测试了onreadystatechange
的值,它打印了2,2,2,而不是0,1,2。
显然有i
值发生了什么事,但我不确定发生了什么。
答案 0 :(得分:0)
此问题可能会简化为
for(var i=0; i<3; i++) {
setTimeout(function() {
console.log(i);
}, 0)
}
它输出3
,3
,3
而不是0
,1
,2
。
问题是函数中的i
与循环中使用的i
相同,并且由于函数是在循环的所有迭代之后调用的,因此始终为3
您可以使用ES6 let
修复它:
for(var i=0; i<3; i++) {
let j=i;
setTimeout(function() {
console.log(j);
}, 0)
}
它起作用,因为let
声明了一个块范围局部变量。你不能使用var
做同样的事情,因为它的范围是当前的执行上下文。
或者您可以使用包装函数:
for(var i=0; i<3; i++) {
(function(j) {
setTimeout(function() {
console.log(j);
}, 0)
})(i);
}
或
for(var i=0; i<3; i++) {
(function() {
var j = i;
setTimeout(function() {
console.log(j);
}, 0)
})();
}
但是最好将它移到循环之外,以避免在每次迭代时重新创建它:
function f(j) {
setTimeout(function() {
console.log(j);
}, 0)
}
for(var i=0; i<3; i++) {
f(i);
}