Закрытие JavaScript внутри циклов - простой практический пример - PullRequest
2599 голосов
/ 15 апреля 2009

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

Это выводит это:

Моя ценность: 3
Моя ценность: 3
Моя ценность: 3

Принимая во внимание, что я хотел бы вывести:

Мое значение: 0
Мое значение: 1
Мое значение: 2


Та же проблема возникает, когда задержка запуска функции вызвана использованием прослушивателей событий:

var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  buttons[i].addEventListener("click", function() {
    // each should log its value.
    console.log("My value: " + i);
  });
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>

… или асинхронный код, например используя обещания:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for (var i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

Каково решение этой основной проблемы?

Ответы [ 43 ]

0 голосов
/ 14 марта 2018

Допустим, вы не используете es6; Вы можете использовать функцию IFFY:

var funcs = [];
for (var i = 0; i < 13; i++) {      
funcs[i] = (function(x) {
console.log("My value: " + i)})(i);}

Но все будет иначе.

0 голосов
/ 25 февраля 2018

Пока этот вопрос старый и на него дан ответ, у меня есть еще одно довольно интересное решение:

var funcs = [];

for (var i = 0; i < 3; i++) {     
  funcs[i] = function() {          
    console.log("My value: " + i); 
 };
}

for (var i = 0; i < 3; i++) {
  funcs[i]();
}

Изменения настолько малы, что почти трудно понять, что я сделал. Я переключил второй итератор с j на i. Это как-то освежает состояние я вовремя, чтобы дать вам желаемый результат. Я сделал это случайно, но это имеет смысл, учитывая предыдущие ответы.

Я написал это, чтобы указать на это небольшое, но очень важное отличие. Надеюсь, это поможет прояснить ситуацию для других учеников, таких как я.

Примечание: я не разделяю это, потому что я думаю, что это правильный ответ. Это ошибочное решение, которое, вероятно, сломается при определенных обстоятельствах. На самом деле, я очень удивлен, что это действительно работает.

0 голосов
/ 13 октября 2017

Уже много действительных ответов на этот вопрос. Не многие используют функциональный подход, хотя. Вот альтернативное решение, использующее метод forEach, который хорошо работает с обратными вызовами и замыканиями:

let arr = [1,2,3];

let myFunc = (val, index) => { console.log('val: '+val+'\nindex: '+index); };

arr.forEach(myFunc);

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