for 循环和词法环境中的闭包

发布于 2024-10-07 01:03:52 字数 602 浏览 2 评论 0原文

简单的情况:我想加载几个具有共同名称和后缀的图像,例如: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

为什么会发生这种情况? 我怎样才能得到我想要的行为?

Simple case: I want to load several images which have a common name and a suffix, e.g: image0.png, image1.png, image2.png ... imageN.png

I'm using a simple for loop:

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";
}

What I'm getting in the Console is:

Image N loaded
Image N loaded
Image N loaded
...
Image N loaded

But what I want should be like this:

Image 0 loaded
Image 1 loaded
Image 2 loaded
...
Image N loaded

Why is this happening?
How can I get my desired behavior?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

洒一地阳光 2024-10-14 01:03:53

函数内的 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 函数捕获该变量的不同实例。

The i inside your function is evaluated when the function is executed, not when you assign it to onload. Your for loop has already completed by the time any of your onload functions fire, so all of them see the final value N.

To capture the current value of i, you need to pass it as a parameter to another function where it can be captured as a local variable:

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";
}

This works because every time you call captureI, a new local variable is created for that instance of captureI. In essence, you are creating N different variables and each onload function captures a different instance of the variable.

许一世地老天荒 2024-10-14 01:03:53

您可以将其包装在闭包中,以避免使用 i 变量(这是一个循环变量)并因此发生变化:

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

这演示了 i(这是一个循环变量)和更改,以及 j,这是一个函数绑定参数,不会更改。

请参阅此处的 jsfiddle:

You can wrap it in a closure to avoid to use i variable, which is a loop variable and thus changes:

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

This demonstrates the difference between i, which is a loop variable and changes, and j, which is a function-bound parameter, which doesn't change.

See the jsfiddle here:

小情绪 2024-10-14 01:03:53

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

Your loop counter variable has been overwritten already. Check out this FAQ entry explaining exactly why it happens and how to work around the issue.

百思不得你姐 2024-10-14 01:03:53

由于变量i是在循环范围之外声明的,因此它在循环完成后保留其最终值。然后,您创建的匿名函数都会绑定到该变量,并且当调用它们时,它们都会获得相同的最终值 N

这个问题

Since the variable i is declared outside the scope of the loop, it retains its final value after the loop has completed. The anonymous functions you're creating then all bind to this variable, and when they're called, they all get the same final value of N.

There's a good discussion of this in this question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文