简单案例:我想加载几个具有通用名称和后缀的图像,例如:image0.png,image1.png,image2.png ... imageN.png
我正在使用一个简单的for循环:
var images = [];
for (var i=1; i<N; i++) {
images[i] = new Image();
images[i].onload = function () {
console.log("Image " + i + " loaded");
};
images[i].src = "image" + i + ".png";
}
我在控制台中获得的是:
Image N loaded
Image N loaded
Image N loaded
...
Image N loaded
但我想要的应该是这样的:
Image 0 loaded
Image 1 loaded
Image 2 loaded
...
Image N loaded
为什么会这样? 我怎样才能达到我想要的行为?
答案 0 :(得分:3)
当函数执行时,将评估函数内的i
,而不是在将其分配给onload
时。您的onload
函数触发时,您的for循环已经完成,因此所有函数都会看到最终值N
。
要捕获i
的当前值,您需要将其作为参数传递给另一个函数,在该函数中它可以作为局部变量捕获:
function captureI(i) {
return function () {
console.log("Image " + i + " loaded");
};
}
var images = [];
for (var i=1; i<N; i++) {
images[i] = new Image();
images[i].onload = captureI(i);
images[i].src = "image" + i + ".png";
}
这是有效的,因为每次调用captureI
时,都会为captureI
的实例创建一个新的局部变量。实质上,您正在创建N
个不同的变量,每个onload
函数捕获变量的不同实例。
答案 1 :(得分:2)
你可以将它包装在一个闭包中,以避免使用i
变量,这是一个循环变量,从而改变:
(function(j) {
images[i].onload = function () {
console.log("Image " + i + ", " + j + " loaded");
};
})(i);
这证明了i
(一个循环变量和更改)与j
(一个函数绑定参数)之间的区别,它不会改变。
请参阅此处的jsfiddle:
答案 2 :(得分:0)
您的循环计数器变量已被覆盖。查看this常见问题解答条目,详细说明其发生的原因以及如何解决此问题。
答案 3 :(得分:0)
由于变量i
声明在循环范围之外,因此它在循环完成后保留其最终值。您正在创建的匿名函数全部绑定到此变量,当它们被调用时,它们都获得相同的最终值N
。
在this question中对此进行了很好的讨论。