Замыкания в цикле for и лексической среде - PullRequest
0 голосов
/ 11 декабря 2010

Простой случай: я хочу загрузить несколько изображений с общим именем и суффиксом, например: 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

Почему это происходит? Как я могу получить желаемое поведение?

Ответы [ 4 ]

3 голосов
/ 11 декабря 2010

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,По сути, вы создаете N разных переменных, и каждая функция onload захватывает отдельный экземпляр переменной.

2 голосов
/ 11 декабря 2010

Вы можете обернуть его в замыкание, чтобы избежать использования переменной i, которая является переменной цикла и, таким образом, изменяется:

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

Это демонстрирует разницу между i, который является цикломпеременная и изменения, и j, который является параметром, связанным с функцией, который не изменяется.

См. jsfiddle здесь:

0 голосов
/ 11 декабря 2010

Поскольку переменная i объявлена ​​вне области действия цикла, она сохраняет свое окончательное значение после завершения цикла.Затем все анонимные функции, которые вы создаете, привязываются к этой переменной, и когда они вызываются, все они получают одинаковое окончательное значение N.

. Это хорошее обсуждение этого вопроса в thisвопрос .

0 голосов
/ 11 декабря 2010

Ваша переменная счетчика цикла уже перезаписана.Ознакомьтесь с этой запиской с часто задаваемыми вопросами, объясняющими, почему это происходит и как обойти проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...