Предположим, у нас есть список простых объектов:
var things = [
{ id: 1, name: 'one' },
{ id: 2, name: 'two' },
{ id: 3, name: 'three' }
];
И нам нужно перебрать эти объекты и зарегистрировать их как параметры для какого-то более позднего события. Наивный подход использует одну и ту же ссылку на объект для всех обратных вызовов, поэтому каждый срабатывает для последнего элемента:
for (var i = 0; i < things.length; i++) {
var o = things[i];
setTimeout(function() { doSomethingWith(o); }, i * 1000);
}
Типичное решение — создать замыкание, ограничивающее область действия нашей ссылки на объект:
for (var i = 0; i < things.length; i++) {
(function() {
var o = things[i];
setTimeout(function() { doSomethingWith(o); }, i * 1000);
})();
}
Если мы не ориентируемся на IE‹9, мы можем полагаться на .forEach()
:
things.forEach(function(o, i) {
var o = things[i];
setTimeout(function() { doSomethingWith(o); }, i * 1000);
});
Но в конечном итоге мы все равно создали своего рода замыкание в этом случае, передав анонимную функцию в forEach()
.
Есть ли способ сделать это без замыкания или ссылки на функцию?
Основная проблема состоит из трех частей:
- Менее важно: ссылка на функцию, переданная в
setTimeout()
(или что-то еще), заставляет вас (меня) чувствовать, что вы создаете замыкание. Итак, у меня есть тенденция забывать внешнее закрытие. - Что еще более важно: дополнительные объявления функций/замыканий поощряют "стрелочный код". Для сложных операций читабельность кода для сложных операций довольно быстро ухудшается, поскольку код мигрирует за пределы экрана ... Это потенциально решается с помощью
.forEach()
в IE> 9, если приложение или руководство по организационному стилю не диктует новую строку + отступ для закрытия. - Самое главное: я был уверен, что есть простой способ справиться с этим. И я чувствую себя глупо из-за того, что не могу думать об этом прямо сейчас.
Может быть, лучше спросить так: Что, черт возьми, мы все делали до того, как начали навязчиво создавать замыкания?