Я видел множество вопросов, предлагающих использовать:
for (var i = 0; i < myArray.length; i++){ /* ... */ }
вместо того:
for (var i in myArray){ /* ... */ }
для массивов из-за непоследовательной итерации ( см. здесь ).
Однако я не могу найти ничего, что бы предпочло объектно-ориентированный цикл:
myArray.forEach(function(item, index){ /* ... */ });
Что мне кажется более интуитивным.
Для моего текущего проекта важна совместимость с IE8, и я рассматриваю возможность использования полифилла Mozilla , однако я не уверен на 100%, как это будет работать.
- Есть ли какие-либо различия между стандартом цикла for (первый пример выше) и реализацией Array.prototype.forEach в современных браузерах?
- Есть ли разница между реализацией современных браузеров и реализацией Mozilla, указанной выше (особенно с IE8)?
- Производительность - это не такая большая проблема, просто согласованность того, какие свойства повторяются.
javascript
arrays
for-loop
internet-explorer-8
iterator
Майкл Льюис
источник
источник
break
выйти изforEach
. Но большим преимуществом является создание новой области с функцией. С полифиллом проблем возникнуть не должно (по крайней мере, я не сталкивался с ними).holes
гдеundefined
должны быть и другие сломанные методы, какslice
иhasOwnProperty
WRT для arraylike объектов DOM. Мое тестирование иes5 shim
показало, что такие методы прокладки соответствуют спецификации (прокладка MDN не проверена).for
петли, это тоsome
, для чего.Array.find()
для выхода из цикла после обнаружения первого совпадения.Ответы:
Наиболее существенное различие между
for
циклом иforEach
методом заключается в том, что с первым вы можетеbreak
выйти из цикла. Вы можете смоделироватьcontinue
, просто вернувшись из функции, переданной вforEach
, но нет никакого способа полностью прекратить цикл.Помимо этого, эти два компонента фактически выполняют одни и те же функции. Еще одно незначительное отличие заключается в области видимости индекса (и всех содержащихся переменных) в цикле for из-за подъема переменных.
// 'i' is scoped to the containing function for (var i = 0; i < arr.length; i++) { ... } // 'i' is scoped to the internal function arr.forEach(function (el, i) { ... });
Однако я считаю, что
forEach
это гораздо более выразительно - оно представляет ваше намерение перебрать каждый элемент массива и предоставляет вам ссылку на элемент, а не только на индекс. В целом, это в основном зависит от личного вкуса, но если вы можете использоватьforEach
, я бы рекомендовал его использовать.Между двумя версиями есть еще несколько существенных различий, особенно в отношении производительности. Фактически, простой цикл for работает значительно лучше, чем
forEach
метод, как демонстрирует этот тест jsperf .Вам решать, нужна ли вам такая производительность, и в большинстве случаев я бы предпочел выразительность скорости. Эта разница в скорости, вероятно, связана с небольшими семантическими различиями между базовым циклом и методом при работе с разреженными массивами, как указано в этом ответе .
Если вам не нужно поведение
forEach
и / или вам нужно преждевременно выйти из цикла, вы можете использовать Lo-Dash_.each
в качестве альтернативы, которая также будет работать в кросс-браузере. Если вы используете jQuery, он также предоставляет аналогичный$.each
, просто обратите внимание на различия в аргументах, передаваемых функции обратного вызова в каждом варианте.(Что касается
forEach
полифила, он должен без проблем работать в старых браузерах, если вы решите пойти по этому пути.)источник
each
ведут себя не так, как спецификация ECMA5forEach
, они склонны рассматривать все массивы как плотные (чтобы избежать ошибок IE, если вы об этом осведомлены). Иначе может быть "попался". В качестве ссылки github.com/es-shims/es5-shim/issues/190Array.prototype.some
которые будут зацикливаться, пока вы не вернете истинное значение или пока оно полностью не пройдет через массив.Array.prototype.every
аналогичен,Array.prototype.some
но останавливается, если вы возвращаете ложное значение.Array.prototype.forEach
какой-либо несовместимой версией может привести к поломке такого количества библиотек, что отказ от нее по этой причине в любом случае не поможет.Вы можете использовать свою собственную функцию foreach, которая будет работать намного лучше, чем Array.forEach
Вы должны добавить это один раз в свой код. Это добавит новую функцию в массив.
function foreach(fn) { var arr = this; var len = arr.length; for(var i=0; i<len; ++i) { fn(arr[i], i); } } Object.defineProperty(Array.prototype, 'customForEach', { enumerable: false, value: foreach });
Затем вы можете использовать его где угодно, например, Array.forEach
[1,2,3].customForEach(function(val, i){ });
Единственная разница в 3 раза быстрее. https://jsperf.com/native-arr-foreach-vs-custom-foreach
ОБНОВЛЕНИЕ: в новой версии Chrome улучшена производительность .forEach (). Однако решение может дать дополнительную производительность в других браузерах.
источник
Многие разработчики (например, Кайл Симпсон) предлагают использовать его,
.forEach
чтобы указать, что массив будет иметь побочный эффект и.map
для чистых функций.for
циклы хорошо подходят в качестве универсального решения для известного количества циклов или любого другого случая, который не подходит, поскольку его легче общаться из-за его широкой поддержки на большинстве языков программирования.например
/* For Loop known number of iterations */ const numberOfSeasons = 4; for (let i = 0; i < numberOfSeasons; i++) { //Do Something } /* Pure transformation */ const arrayToBeUppercased = ['www', 'html', 'js', 'us']; const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase)); /* Impure, side-effects with .forEach */ const acronymsHolder = []; ['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));
С точки зрения конвенций, это кажется лучшим, однако сообщество на самом деле еще не пришло к соглашению о новых
for in
циклах итерационного протокола . В целом, я считаю хорошей идеей следовать концепциям FP, которые сообщество JS, похоже, готово принять.источник