2010-12-11 58 views
0

简单案例:我想要加载多个具有通用名称和后缀的图像,例如:image0.png,image1.png,image2.png ... imageN.pngfor循环和词汇环境中的闭包

我使用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

可能重复[关闭的Javascript内循环 - 简单实用的例子(http://stackoverflow.com/questions/750486/javascript-closure -inside-loops-simple-practical-example) – 2010-12-11 19:40:12

回答

3

i在函数内部执行函数时执行,而不是在将它分配给onload时执行。您的for循环在您的onload函数触发时已经完成,所以它们都会看到最终值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。本质上,您正在创建不同的变量,并且每个onload函数捕获变量的不同实例。

+0

感谢您的最后解释。 – 2010-12-11 18:56:52

0

您的循环计数器变量已被覆盖。查看this常见问题解答条目,解释其发生的原因以及如何解决该问题。

0

由于变量i被声明为循环范围之外,所以在循环完成后它将保留其最终值。你创建的匿名函数都绑定到这个变量上,当它们被调用时,它们都会得到相同的最终值N

this question有很好的讨论。

+0

这将为所有图像提供N-1 :-) – 2010-12-11 19:02:22

2

可以把它包装在封闭,以避免使用i变量,这是一个循环变量,从而改变:

(function(j) { 
    images[i].onload = function() { 
     console.log("Image " + i + ", " + j + " loaded"); 
    }; 
})(i); 

这证明i之间的差异,这是一个循环变量和变化,并j,这是一个函数绑定的参数,它不会改变。

想在这里看到的jsfiddle:中