Как я могу просмотреть все записи в массиве с помощью JavaScript?
Я подумал, что это что-то вроде этого:
forEach(instance in theArray)
Где theArray
- мой массив, но это кажется неправильным.
TL; DR
for-in
если вы не используете его с защитой или, по крайней мере, не знаете, почему он может вас укусить.Ваши лучшие ставки обычно
Но есть еще много, чтобы исследовать, читать дальше...
JavaScript имеет мощную семантику для циклического преобразования массивов и объектов типа массива. Я разделил ответ на две части: варианты для подлинных массивов и варианты для вещей, которые похожи только на массивы, такие как объект arguments
, другие итерируемые объекты (ES2015+), коллекции DOM и т.д.
Я быстро заметлю, что теперь вы можете использовать опции ES2015, даже на двигателях ES5, путем пересылки ES2015 на ES5. Найдите "ES2015 transpiling"/"ES6 transpiling" для более...
Хорошо, посмотрим на наши варианты:
У вас есть три варианта в ECMAScript 5 ("ES5"), версия, наиболее широко поддерживаемая на данный момент, и еще две добавленные в ECMAScript 2015 ("ES2015", "ES6"):
forEach
и связанные с ним (ES5+)for
циклаfor-in
for-of
(использовать итератор неявно) (ES2015+)Детали:
forEach
и связанные с ним В любой неопределенно современной среде (так, а не в IE8), где у вас есть доступ к функциям Array
добавленным ES5 (напрямую или с использованием полиполнений), вы можете использовать forEach
( spec
| MDN
):
var a = ["a", "b", "c"];
a.forEach(function(entry) {
console.log(entry);
});
forEach
принимает функцию обратного вызова и, необязательно, значение, используемое как this
при вызове этого обратного вызова (не используется выше). Обратный вызов вызывается для каждой записи в массиве, чтобы пропустить несуществующие записи в разреженных массивах. Хотя я использовал только один аргумент выше, обратный вызов вызывается с тремя: значение каждой записи, индекс этой записи и ссылка на массив, который вы повторяете (в случае, если ваша функция еще не имеет его).
Если вы не поддерживаете устаревшие браузеры, такие как IE8 (которые NetApps показывает на уровне более 4% рынка на момент написания этой статьи в сентябре 2016 года), вы можете с радостью использовать forEach
на универсальной веб-странице без прокладки. Если вам нужно поддерживать устаревшие браузеры, легко выполнить операцию shimming/polyfilling forEach
(найдите "es5 shim" для нескольких опций).
forEach
имеет то преимущество, что вам не нужно объявлять индексирование и переменные значения в области содержимого, поскольку они поставляются в качестве аргументов функции итерации и настолько хорошо ориентированы на эту итерацию.
Если вы беспокоитесь о затратах времени выполнения вызова функции для каждой записи массива, не будьте; подробности.
Кроме того, forEach
- это функция "loop through them all", но ES5 определил несколько других полезных "проработок через функции массива и вещей", в том числе:
every
(останавливает цикл в первый раз, когда обратный вызов возвращает false
или что-то ложное)some
(останавливает цикл в первый раз, когда обратный вызов возвращает true
или что-то правдоподобное)filter
(создает новый массив, включающий элементы, в которых функция фильтра возвращает true
и опускает те, где она возвращает false
)map
(создает новый массив из значений, возвращаемых обратным вызовом)reduce
(наращивает значение, повторно вызывая обратный вызов, передавая предыдущие значения, см. спецификацию для деталей, полезно для суммирования содержимого массива и многих других вещей)reduceRight
(например, reduce
, но работает в нисходящем, а не восходящем порядке)for
циклаИногда старые способы являются лучшими:
var index;
var a = ["a", "b", "c"];
for (index = 0; index < a.length; ++index) {
console.log(a[index]);
}
Если длина массива не будет меняться в течение цикла, и его производительность чувствительного кода (маловероятно), чуть более сложный вариант захвата длиной фронта может быть чуть - чуть быстрее:
var index, len;
var a = ["a", "b", "c"];
for (index = 0, len = a.length; index < len; ++index) {
console.log(a[index]);
}
И/или считая назад:
var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --index) {
console.log(a[index]);
}
Но с современными механизмами JavaScript вам редко приходится выкапывать этот последний сок.
В ES2015 и выше вы можете сделать свой индекс и переменные значений локальными for
цикла for
:
let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
let value = a[index];
}
//console.log(index); // Would cause "ReferenceError: index is not defined"
//console.log(value); // Would cause "ReferenceError: value is not defined"
И когда вы это делаете, не только value
но и index
воссоздаются для каждой итерации цикла, то есть замыкания, созданные в теге цикла, содержат ссылку на index
(и value
), созданный для этой конкретной итерации:
let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
divs[index].addEventListener('click', e => {
alert("Index is: " + index);
});
}
Если у вас было пять div, вы бы получили "Index is: 0", если вы нажали первый и "Index is: 4", если вы нажали последний. Это не работает, если вы используете var
вместо let
.
for-in
Вы получите люди, рассказывающие вам использовать for-in
, но это не то, что for-in
для. for-in
запишутся через перечислимые свойства объекта, а не индексы массива. Заказ не гарантируется, даже в ES2015 (ES6). ES2015 делает определить порядок свойств объекта ( с помощью [[OwnPropertyKeys]]
, [[Enumerate]]
, и вещи, которые используют их как Object.getOwnPropertyKeys
), но он не определяет, что for-in
будет следовать, что заказ. (Подробности в этом другом ответе.)
Тем не менее, это может быть полезно, особенно для разреженных массивов, если вы используете соответствующие меры предосторожности:
// 'a' is a sparse array
var key;
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (key in a) {
if (a.hasOwnProperty(key) && // These are explained
/^0$|^[1-9]\d*$/.test(key) && // and then hidden
key <= 4294967294 // away below
) {
console.log(a[key]);
}
}
Обратите внимание на две проверки:
То, что объект имеет свое собственное свойство под этим именем (а не тот, который он наследует от своего прототипа), и
То, что ключ представляет собой числовую строку base-10 в своей обычной строковой форме, и ее значение <= 2 ^ 32 - 2 (что составляет 4 294 967 294). Откуда это число? Это часть определения индекса массива в спецификации. Другие числа (нецелые числа, отрицательные числа, числа больше 2 ^ 32 - 2) не являются индексами массива. Причиной 2 ^ 32 - 2 является то, что делает наибольшее значение индекса менее 2 ^ 32 - 1, что является максимальным значением length
массива. (Например, длина массива соответствует 32-разрядному целому числу без знака.) (Подтверждение на RobG для указания в комментарии к моему сообщению в блоге, что мой предыдущий тест был не совсем прав).
Это крошечный бит добавочных накладных расходов для каждой итерации циклов на большинстве массивов, но если у вас есть разреженный массив, это может быть более эффективным способом для цикла, потому что это только циклы для записей, которые на самом деле существуют. Например, для массива выше, мы зацикливаем три раза (для клавиш "0"
, "10"
и "10000"
- помните, это строки), а не 10 001 раз.
Теперь вы не захотите писать это каждый раз, так что вы можете поместить это в свой инструментарий:
function arrayHasOwnIndex(array, prop) {
return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2
}
И тогда мы будем использовать его так:
for (key in a) {
if (arrayHasOwnIndex(a, key)) {
console.log(a[key]);
}
}
Или, если вас интересует только тест "достаточно хороший для большинства случаев", вы можете использовать это, но пока оно близко, это не совсем правильно:
for (key in a) {
// "Good enough" for most cases
if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) {
console.log(a[key]);
}
}
for-of
(используйте итератор неявно) (ES2015+) ES2015 добавляет итераторы к JavaScript. Самый простой способ использования итераторов - это новый оператор for-of
. Это выглядит так:
var val;
var a = ["a", "b", "c"];
for (val of a) {
console.log(val);
}
Вывод:
a b c
Под обложками, который получает итератор из массива и проходит через него, получает значения из него. У этого нет проблемы, связанной с использованием for-in
, поскольку он использует итератор, определенный объектом (массивом), а массивы определяют, что их итераторы повторяют свои записи (а не их свойства). В отличие от for-in
в ES5, порядок, в котором просматриваются записи, представляет собой числовой порядок их индексов.
Иногда вы можете явно использовать итератор. Вы тоже можете это сделать, хотя это намного clunkier чем for-of
. Это выглядит так:
var a = ["a", "b", "c"];
var it = a.values();
var entry;
while (!(entry = it.next()).done) {
console.log(entry.value);
}
Итератор - это объект, соответствующий определению Iterator в спецификации. Его next
метод возвращает новый объект результата каждый раз, когда вы его вызываете. Объект result имеет свойство, done
, сообщает нам, было ли это сделано, и value
свойства со значением для этой итерации. (done
необязательно, если оно было бы false
, value
является необязательным, если оно не undefined
).
Значение value
варьируется в зависимости от итератора; массивы поддерживают (по крайней мере) три функции, возвращающие итераторы:
values()
: Это тот, который я использовал выше. Он возвращает итератор, где каждое value
представляет собой запись массива для этой итерации ("a"
, "b"
и "c"
в примере ранее).keys()
: Возвращает итератор, где каждое value
является ключевым для этой итерации (так что для нашей выше, что будет a
"0"
, а затем "1"
, а затем "2"
).entries()
: возвращает итератор, где каждое value
представляет собой массив в форме [key, value]
для этой итерации. Помимо истинных массивов, существуют также подобные массиву объекты, которые имеют свойство length
и свойства с числовыми именами: экземпляры NodeList
, объект arguments
и т.д. Как мы NodeList
их содержимое?
По крайней мере некоторые и, возможно, большинство или даже все из вышеперечисленных массивов часто применяются одинаково хорошо для объектов типа массива:
Использовать forEach
и связанные с ним (ES5+)
Различные функции на Array.prototype
являются "преднамеренно генерическими" и обычно могут использоваться для объектов, подобных массиву, посредством Function#call
Function#apply
или Function#apply
. (См. Оговорку для объектов, предоставленных хостом, в конце этого ответа, но это редкая проблема.)
Предположим, вы хотели использовать forEach
в childNodes
Node
childNodes
. Вы сделали бы это:
Array.prototype.forEach.call(node.childNodes, function(child) {
// Do something with 'child'
});
Если вы собираетесь сделать это много, вы можете захотеть получить копию ссылки на функцию в переменной для повторного использования, например:
// (This is all presumably in some scoping function)
var forEach = Array.prototype.forEach;
// Then later...
forEach.call(node.childNodes, function(child) {
// Do something with 'child'
});
Используйте простой for
цикла
Очевидно, простой цикл for
применяется к объектам, подобным массиву.
Правильно использовать for-in
for-in
с теми же гарантиями, что и с массивом, должен работать и с подобными массиву объектами; может потребоваться оговорка для объектов, предоставленных хостом, на № 1 выше.
Использовать for-of
(использовать итератор неявно) (ES2015+)
for-of
будет использовать итератор, предоставляемый объектом (если таковой имеется); мы должны будем увидеть, как это происходит с различными подобными массивом объектами, особенно с хост файлами. Например, спецификация для NodeList
от querySelectorAll
была обновлена для поддержки итерации. Спецификацию для HTMLCollection
из getElementsByTagName
не было.
Использовать итератор явно (ES2015+)
См. № 4, нам нужно посмотреть, как разворачиваются итераторы.
В других случаях вы можете преобразовать объект, подобный массиву, в истинный массив. Делать это на удивление легко:
Использовать метод slice
массивов
Мы можем использовать метод slice
массивов, который, как и другие методы, упомянутые выше, является "преднамеренно общим" и поэтому может использоваться с подобными массиву объектами, например:
var trueArray = Array.prototype.slice.call(arrayLikeObject);
Так, например, если мы хотим преобразовать NodeList
в настоящий массив, мы могли бы сделать это:
var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
См. "Предостережение для объектов, предоставляемых хостом" ниже. В частности, обратите внимание, что это не удастся в IE8 и ранее, что не позволяет использовать объекты, предоставленные хостом, как this
.
Использовать синтаксис распространения (...
)
Также возможно использовать синтаксис распространения ES2015 с механизмами JavaScript, которые поддерживают эту функцию:
var trueArray = [...iterableObject];
Так, например, если мы хотим преобразовать NodeList
в истинный массив, с синтаксисом распространения это становится довольно кратким:
var divs = [...document.querySelectorAll("div")];
Используйте Array.from
(spec) | (MDN)
Array.from
(ES2015+, но легко поли заполнен) создает массив из объекта, подобного массиву, при необходимости сначала передавая записи через функцию сопоставления. Так:
var divs = Array.from(document.querySelectorAll("div"));
Или, если вы хотите получить массив имен тегов для элементов с заданным классом, вы должны использовать функцию сопоставления:
// Arrow function (ES2015):
var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
// Standard function (since 'Array.from' can be shimmed):
var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
return element.tagName;
});
Если вы используете функции Array.prototype
с объектами, подобными хостам (списки DOM и другие вещи, предоставляемые браузером, а не движком JavaScript), вы должны быть уверены, что будете тестировать в своих целевых средах, чтобы убедиться, что предоставленный хост объект ведет себя правильно. Большинство из них ведут себя правильно (сейчас), но важно проверить. Причина в том, что большинство методов Array.prototype
которые вы, вероятно, захотите использовать, полагаются на предоставленный хостом объект, давая честный ответ на абстрактную [[HasProperty]]
. На момент написания этой статьи браузеры очень хорошо справились с этим, но спецификация 5.1 позволила предположить, что объект, предоставляемый хостом, может быть не честным. Это в §8.6.2, несколько абзацев ниже большой таблицы в начале этого раздела), где говорится:
Хост-объекты могут реализовывать эти внутренние методы любым способом, если не указано иное; например, одна возможность заключается в том, что
[[Get]]
и[[Put]]
для определенного объекта хоста действительно извлекают и сохраняют значения свойств, но[[HasProperty]]
всегда генерируют false.
(Я не мог найти эквивалентную формулировку в ES2015 спецификации, но он обязан еще быть.) Опять же, как это написанием общих хоста предоставляемого массива типа объектов в современных браузерах [ NodeList
экземпляров, например] сделать ручка [[HasProperty]]
правильно, но важно проверить.)
.forEach
не может быть эффективно сломан. Вы должны бросить исключение, чтобы выполнить перерыв.
some
. (Я бы предпочел также разрешить взломать forEach
, но они не спросили меня. ;-))
Изменить: этот ответ безнадежно устарел. Для более современного подхода посмотрите на методы, доступные в массиве. Интересующие методы могут быть:
Стандартный способ итерации массива в JavaScript - это ваниль for
-loop:
var length = arr.length,
element = null;
for (var i = 0; i < length; i++) {
element = arr[i];
// Do something with element
}
Обратите внимание, однако, что этот подход хорош, только если у вас плотный массив, и каждый индекс занят элементом. Если массив разреженный, то при таком подходе вы можете столкнуться с проблемами производительности, так как вы будете перебирать множество индексов, которые на самом деле не существуют в массиве. В этом случае лучше использовать for.. in
-loop. Однако вы должны использовать соответствующие меры предосторожности, чтобы гарантировать, что будут действовать только требуемые свойства массива (то есть элементы массива), поскольку for..in
-loop также будет перечисляться в устаревших браузерах, или если дополнительные свойства определены как enumerable
.
В ECMAScript 5 для прототипа массива будет использоваться метод forEach, но он не поддерживается в устаревших браузерах. Поэтому, чтобы иметь возможность использовать его последовательно, вы должны либо иметь среду, которая его поддерживает (например, Node.js для серверного JavaScript), либо использовать "Polyfill". Polyfill для этой функциональности, однако, тривиален, и, поскольку он делает код более легким для чтения, его стоит включить в Polyfill.
for(instance in objArray)
не является правильным использованием? это выглядит более простым для меня, но я слышал, вы говорите об этом как о неправильном способе использования?
Если вы используете библиотеку jQuery, вы можете использовать jQuery.each:
$.each(yourArray, function(index, value) {
// do your stuff here
});
EDIT:
В соответствии с вопросом пользователь хочет код в javascript вместо jquery, поэтому редактирование
var length = yourArray.length;
for (var i = 0; i < length; i++) {
// Do something with yourArray[i].
}
Я думаю, что обратное для цикла заслуживает упоминания здесь:
for (var i = array.length; i--; ) {
// process array[i]
}
len
или сравнивать ее с array.length
на каждой итерации, которая может быть минутной оптимизацией.array[i]
), тогда прямой цикл пропускает элемент, который сдвинут влево в положение я или перепроверить i-й элемент, который был сдвинут вправо. В традиционном цикле вы можете обновить i, чтобы указать на следующий элемент, который нуждается в обработке - 1, но просто изменить направление итерации часто проще и более элегантное решение.forEach()
и до ES6 for ... of
.Некоторые разработчики используют обратный цикл для по умолчанию, если нет веской причины для перехода вперед.
Хотя прирост производительности обычно незначителен, это крики:
"Просто сделайте это для каждого элемента в списке, я не забочусь о заказе!"
Однако на практике это не на самом деле надежное указание на намерение, поскольку оно неотличимо от тех случаев, когда вы делаем заботиться о заказе и действительно выполняете нужна для обратной петли. Таким образом, на самом деле потребуется еще одна конструкция, чтобы точно выразить намерение "не заботиться", что в настоящее время недоступно на большинстве языков, включая ECMAScript, но которое можно назвать, например, forEachUnordered()
.
Если порядок не имеет значения, а эффективность вызывает озабоченность (в самом внутреннем цикле движка игры или анимации), тогда может быть приемлемым использовать цикл обратного цикла, к рисунку. Просто помните, что просмотр обратного цикла в существующем коде не обязательно означает, что порядок не имеет значения!
В целом для кода более высокого уровня, где ясность и безопасность больше беспокоят, я бы рекомендовал использовать Array::forEach
как ваш шаблон по умолчанию:
for
и while
.)Затем, когда вы видите обратное для цикла в своем коде, это намек на то, что он поменялся по уважительной причине (возможно, одна из причин, описанных выше). И, увидев традиционный цикл вперед, можно указать, что может произойти переключение.
(Если обсуждение намерения не имеет для вас никакого смысла, то вам и вашему коду может быть полезно посмотреть лекцию Крокфорда на Стиль программирования и ваш мозг.)
for (var i = 0; i < array.length; i++) { ... } // Forwards
for (var i = array.length; i--; ) { ... } // Reverse
Вы заметите, что i--
является средним предложением (где мы обычно видим сравнение), а последнее предложение пусто (где мы обычно видим i++
). Это означает, что i--
также используется как условие продолжения. Реально, он выполняется и проверяется перед каждой итерацией.
Как он может начинаться с array.length
без взрыва?
Поскольку i--
запускается перед каждой итерацией, на первой итерации мы фактически получаем доступ к элементу в array.length - 1
, который избегает любых проблем с элементами Array-out-of-bounds undefined
.
Почему он не останавливает итерацию перед индексом 0?
Цикл прекратит итерацию, когда условие i--
оценивает значение false (когда оно дает 0).
Фокус в том, что в отличие от --i
, конечный оператор i--
уменьшает i
, но дает значение до декремента. Ваша консоль может продемонстрировать это:
> var i = 5; [i, i--, i];
[5, 5, 4]
Итак, на последней итерации я ранее был 1, а выражение i--
меняло его на 0, но на самом деле дает 1 (правдиво), и поэтому условие проходит. На следующей итерации i--
меняет я на -1, но дает 0 (falsey), заставляя выполнение немедленно выходить из нижней части цикла.
В традиционном forwards for loop, i++
и ++i
взаимозаменяемы (как указывает Дуглас Крокфорд). Однако в обратном для цикла, поскольку наш декремент также является выражением нашего условия, мы должны придерживаться i--
, если мы хотим обработать элемент в индексе 0.
Некоторым людям нравится рисовать небольшую стрелку в обратном цикле for
и заканчивать миганием:
for (var i = array.length; i --> 0 ;) {
Кредиты идут в WYL, чтобы показать мне преимущества и ужасы обратного цикла.
Некоторые C -язычные языки используют foreach
для циклического перебора. В JavaScript это делается с помощью структуры for..in
:
var index,
value;
for (index in obj) {
value = obj[index];
}
Есть улов. for..in
будет проходить через каждый из перечисляемых объектов и членов на его прототипе. Чтобы избежать считывания значений, которые наследуются через прототип объекта, просто проверьте, принадлежит ли свойство объекту:
for (i in obj) {
if (obj.hasOwnProperty(i)) {
//do stuff
}
}
Кроме того, ECMAScript 5 добавил foreach
to Array.prototype
, который может использоваться для перечисления по массиву с использованием calback (polyfill находится в документах, поэтому вы можете использовать его для более старых браузеров):
arr.forEach(function (val, index, theArray) {
//do stuff
});
Важно отметить, что Array.prototype.forEach
не прерывается, когда обратный вызов возвращает false
. jQuery и Underscore.js предоставляют свои собственные варианты each
, чтобы обеспечить петли, которые могут быть закорочены.
each
методы, которые позволяют return false
для выхода из цикла, но для forEach
это не вариант. Можно использовать внешний флаг (т. Е. if (flag) return;
но это только помешает выполнению остальной части тела функции, forEach
будет продолжать перебирать всю коллекцию.
Если вы хотите перебрать массив, используйте стандартный трехчастный цикл for
.
for (var i = 0; i < myArray.length; i++) {
var arrayItem = myArray[i];
}
Вы можете получить некоторую оптимизацию производительности путем кэширования myArray.length
или повторения ее назад.
length
. ;)
Если вы не против опустошения массива:
var x;
while(x = y.pop()){
alert(x); //do something
}
x
будет содержать последнее значение y
, и оно будет удалено из массива. Вы также можете использовать shift()
, который даст и удалит первый элемент из y
.
[1, 2, undefined, 3]
.
[1, 2, 0, 3]
или [true, true, false, true]
Я знаю, что это старый пост, и есть много замечательных ответов. Для немного более полноты я решил, что я бы выбрал другой, используя AngularJS. Конечно, это применимо только в том случае, если вы используете Angular, очевидно, тем не менее, я все равно хочу его поместить.
angular.forEach
принимает 2 аргумента и необязательный третий аргумент. Первый аргумент - это объект (массив) для итерации, второй аргумент - функция итератора, а необязательный третий аргумент - это контекст объекта (в основном называемый внутри цикла как 'this'.
Существуют разные способы использования цикла forEach для angular. Самый простой и, вероятно, наиболее используемый -
var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
//item will be each element in the array
//do something
});
Другой способ, который полезен для копирования элементов из одного массива в другой, -
var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);
Хотя вам не обязательно это делать, вы можете просто сделать следующее и это эквивалентно предыдущему примеру:
angular.forEach(temp, function(item) {
temp2.push(item);
});
Теперь есть плюсы и минусы использования функции angular.forEach
, в отличие от встроенного в ванили ароматизированного цикла for
.
Pros
angular.forEach
будет использовать цикл ES5 forEach. Теперь я получу эффективность в разделе cons, поскольку петли forEach намного медленнее, чем циклы for. Я упоминаю об этом как о профессионале, потому что приятно быть последовательным и стандартизованным.Рассмотрим следующие два вложенных цикла, которые делают то же самое. Скажем, что у нас есть 2 массива объектов, и каждый объект содержит массив результатов, каждый из которых имеет свойство Value, которое содержит строку (или что-то еще). И пусть говорят, что нам нужно перебирать каждый из результатов, и если они равны, то выполните какое-то действие:
angular.forEach(obj1.results, function(result1) {
angular.forEach(obj2.results, function(result2) {
if (result1.Value === result2.Value) {
//do something
}
});
});
//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
for (var j = 0; j < obj2.results.length; j++) {
if (obj1.results[i].Value === obj2.results[j].Value) {
//do something
}
}
}
Конечно, это очень простой гипотетический пример, но я написал тройку, встроенную для циклов, используя второй подход, и было очень трудно читать и писать по этому поводу.
против
angular.forEach
, и нативный forEach
, если на то пошло, настолько медленнее, чем обычный цикл for
.... о на 90% медленнее. Поэтому для больших наборов данных лучше всего придерживаться встроенного цикла for
.continue
на самом деле поддерживается авария", чтобы продолжить в angular.forEach
, вы просто положили оператор return;
в функцию типа angular.forEach(array, function(item) { if (someConditionIsTrue) return; });
, который приведет к тому, что он продолжит работу для этой итерации. Это также связано с тем, что нативный forEach
не поддерживает разрыв или продолжается либо.Я уверен, что есть и другие плюсы и минусы, и, пожалуйста, не стесняйтесь добавлять все, что сочтете нужным. Я чувствую, что в нижней строке, если вам нужна эффективность, придерживайтесь только собственного цикла for
для ваших нужд цикла. Но, если ваши наборы данных меньше, и некоторая эффективность в порядке, чтобы отказаться от обмена на удобочитаемость и возможность записи, то непременно бросьте angular.forEach
на этого плохого мальчика.
Легким решением теперь будет использование библиотеки underscore.js. Он предоставляет множество полезных инструментов, таких как each
и автоматически делегирует задание на нативный forEach
, если он доступен.
Пример CodePen о том, как он работает:
var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});
Array.prototype.forEach()
.for each (variable in object)
устарел как часть ECMA-357 (EAX).for (variable of object)
в качестве части предложения Harmony (ECMAScript 6).A forEach (см. в jsFiddle):
function forEach(list,callback) {
var length = list.length;
for (var n = 0; n < length; n++) {
callback.call(list[n]);
}
}
var myArray = ['hello','world'];
forEach(
myArray,
function(){
alert(this); // do something
}
);
В jQuery существует три реализации foreach
следующим образом.
var a = [3,2];
$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3
Вероятно, цикл for(i = 0; i < array.length; i++)
не лучший выбор. Зачем? Если у вас есть это:
var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";
Метод вызовет от array[0]
до array[2]
. Во-первых, это сначала будет ссылаться на переменные, которых у вас даже нет, во-вторых, у вас не будет переменных в массиве, а в-третьих, это сделает код более смелым. Послушайте, это то, что я использую:
for(var i in array){
var el = array[i];
//If you want 'i' to be INT just put parseInt(i)
//Do something with el
}
И если вы хотите, чтобы это была функция, вы можете сделать это:
function foreach(array, call){
for(var i in array){
call(array[i]);
}
}
Если вы хотите сломать, немного логичнее:
function foreach(array, call){
for(var i in array){
if(call(array[i]) == false){
break;
}
}
}
Пример:
foreach(array, function(el){
if(el != "!"){
console.log(el);
} else {
console.log(el+"!!");
}
});
Он возвращает:
//Hello
//World
//!!!
Как и ES6:
list = [0, 1, 2, 3]
for (let obj of list) {
console.log(obj)
}
Где of
избегает странностей, связанных с in
, и заставляет его работать как цикл for
любого другого языка, а let
связывает i
внутри цикла, а не внутри функции.
Скобки ({}
) могут быть опущены, когда есть только одна команда (например, в примере выше).
Это итератор для нерезкого списка, где индекс начинается с 0, что является типичным сценарием при работе с document.getElementsByTagName или document.querySelectorAll)
function each( fn, data ) {
if(typeof fn == 'string')
eval('fn = function(data, i){' + fn + '}');
for(var i=0, L=this.length; i < L; i++)
fn.call( this[i], data, i );
return this;
}
Array.prototype.each = each;
Примеры использования:
Пример # 1
var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]
Пример # 2
each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');
Каждый тэг p получает class="blue"
Пример # 3
each.call(document.getElementsByTagName('p'),
"if( i % 2 == 0) this.className = data;",
'red'
);
Каждый другой тег p получает class="red"
>
Пример # 4
each.call(document.querySelectorAll('p.blue'),
function(newClass, i) {
if( i < 20 )
this.className = newClass;
}, 'green'
);
И, наконец, первые 20 синих p-тэгов меняются на зеленый
Предостережение при использовании функции string как функции: функция создается вне контекста и должна использоваться только там, где вы уверены в переменном охвате. В противном случае лучше передать функции, где область обзора более интуитивно понятна.
Для for each
цикла в родном JavaScript нет ни одного. Вы можете использовать библиотеки, чтобы получить эту функцию (я рекомендую Underscore.js), используйте простой for
в цикле.
for (var instance in objects) {
...
}
Тем не менее, обратите внимание, что могут быть причины, чтобы использовать еще проще for
цикла (см переполнением стека вопрос Почему используется "для... в" с массивом итерационного такой плохой идеей?)
var instance;
for (var i=0; i < objects.length; i++) {
var instance = objects[i];
...
}
Существует несколько способов циклического преобразования массива в JavaScript, как показано ниже:
для - это самый распространенный. Полный блок кода для циклирования
var languages = ["JAVA", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>
while - loop, пока выполняется условие. Кажется, это самый быстрый цикл
var text = "";
var i = 0;
while (i < 10) {
text += i + ") something<br>";
i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>
do/while - также цикл через блок кода, пока условие истинно, будет выполняться как минимум один раз
var text = ""
var i = 0;
do {
text += i + ") something <br>";
i++;
}
while (i < 10);
document.getElementById("example").innerHTML = text;
<p id="example"></p>
Функциональные циклы - forEach
, map
, filter
, также reduce
(они прокручивают функцию, но используются, если вам нужно что-то делать с вашим массивом и т.д.
// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>
Для получения дополнительной информации и примеров о функциональном программировании на массивах, посмотрите на сообщение в блоге. Функциональное программирование в JavaScript: отображение, фильтрация и уменьшение.
forEach
- это не «функциональный» цикл, поскольку он не возвращает новый Array
(на самом деле он ничего не возвращает), он просто повторяется.
ECMAScript5 (версия на Javascript) для работы с массивами.
forEach. Итерирует каждый элемент массива и делает все, что вам нужно, с каждым элементом.
['C', 'D', 'E'].forEach(function(element, index) {
console.log(element + " is the #" + (index+1) + " in musical scale");
});
// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale
В случае, более заинтересованный в работе над массивом с использованием некоторой встроенной функции.
map. Он создает новый массив с результатом функции обратного вызова. Этот метод хорош для использования, когда вам нужно отформатировать элементы вашего массива.
// Let upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
return elem.toUpperCase();
});
// Output: ['BOB', 'JOE', 'JEN']
уменьшить. Как видно из названия, он уменьшает массив до одного значения, вызывая передачу данной функции в элементе currenct и результате предыдущего выполнения.
[1,2,3,4].reduce(function(previous, current) {
return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10
каждый - возвращает true или false, если все элементы массива проходят тест в функции обратного вызова.
// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
return elem >= 18;
});
// Output: false
фильтр - очень похоже на каждый, кроме того, что фильтр возвращает массив с элементами, возвращающими true для данной функции.
// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
return (elem % 2 == 0)
});
// Output: [2,4,6]
Надеюсь, это будет полезно.
Там нет встроенной способности взломать для forEach
. Чтобы прервать выполнение, используйте Array#some
как показано ниже:
[1,2,3].some(function(number) {
return number === 1;
});
Это работает, потому что some
возвращают true, как только любой из обратных вызовов, выполненный в порядке массива, возвращает true, короткое замыкание выполнения остальных. Оригинальный ответ см. В прототипе Array для некоторых
Я также хотел бы добавить это как состав обратной петли и ответ выше для тех, кто хотел бы также использовать этот синтаксис.
var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
console.log(item);
}
Плюсы:
Выгода для этого: у вас есть ссылка уже в первом, что не нужно будет объявлять позже с другой строкой. Это удобно при циклическом перемещении по массиву объектов.
Минусы:
Это будет прерываться всякий раз, когда ссылка ложна - false (undefined и т.д.). Однако это можно использовать как преимущество. Однако, это сделало бы его немного труднее читать. А также в зависимости от браузера он может быть "не" оптимизирован для работы быстрее оригинального.
jQuery, используя $.map
:
var data = [1, 2, 3, 4, 5, 6, 7];
var newData = $.map(data, function(element) {
if (element % 2 == 0) {
return element;
}
});
// newData = [2, 4, 6];
[undefined, 2, undefined, 4, undefined, 6, undefined]
.
Использование циклов с оператором деструктуризации и распространения ES6
Разрушение и использование оператора распространения оказались весьма полезными для новичков в ES6 как более удобочитаемые/эстетичные, хотя некоторые ветераны javascript могут посчитать это грязным, юниоры или некоторые другие люди могут найти его полезным.
Следующие примеры будут использовать
for...of
оператора и метода.forEach
.Примеры 6, 7 и 8 могут использоваться с любыми функциональными циклами, такими как
.map
,.filter
,.reduce
,.sort
,.every
,.some
, для получения дополнительной информации об этих методах проверьте объект Array.
Пример 1: Нормально for...of
цикла - здесь нет хитростей.
let arrSimple = ['a', 'b', 'c'];
for (let letter of arrSimple) {
console.log(letter);
}
Пример 2: разделение слов на символы
let arrFruits = ['apple', 'orange', 'banana'];
for (let [firstLetter, ...restOfTheWord] of arrFruits) {
// Create a shallow copy using the spread operator
let [lastLetter] = [...restOfTheWord].reverse();
console.log(firstLetter, lastLetter, restOfTheWord);
}
Пример 3: Цикл с key
и value
// let arrSimple = ['a', 'b', 'c'];
// Instead of keeping an index in 'i' as per example 'for(let i = 0 ; i<arrSimple.length;i++)'
// this example will use a multi-dimensional array of the following format type:
// 'arrWithIndex: [number, string][]'
let arrWithIndex = [
[0, 'a'],
[1, 'b'],
[2, 'c'],
];
// Same thing can be achieved using '.map' method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);
// Same thing can be achieved using 'Object.entries'
// NOTE: 'Object.entries' method doesn't work on internet explorer unless it polyfilled
// let arrWithIndex = Object.entries(arrSimple);
for (let [key, value] of arrWithIndex) {
console.log(key, value);
}
Пример 4: Получить свойства объекта встроенными
let arrWithObjects = [{
name: 'Jon',
age: 32
},
{
name: 'Elise',
age: 33
}
];
for (let { name, age: aliasForAge } of arrWithObjects) {
console.log(name, aliasForAge);
}
Пример 5: Получить глубокие свойства объекта того, что вам нужно
let arrWithObjectsWithArr = [{
name: 'Jon',
age: 32,
tags: ['driver', 'chef', 'jogger']
},
{
name: 'Elise',
age: 33,
tags: ['best chef', 'singer', 'dancer']
}
];
for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
console.log(name, firstItemFromTags, restOfTags);
}
Пример 6: Используется ли пример 3 с .forEach
let arrWithIndex = [
[0, 'a'],
[1, 'b'],
[2, 'c'],
];
// Not to be confused here, 'forEachIndex' is the real index
// 'mappedIndex' was created by "another user", so you can't really trust it
arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
console.log(forEachIndex, mappedIndex, item);
});
Пример 7: Используется ли пример 4 с .forEach
let arrWithObjects = [{
name: 'Jon',
age: 32
},
{
name: 'Elise',
age: 33
}
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parenthesis
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
console.log(name, aliasForAge)
});
Пример 8. Используется ли пример 5 с .forEach
let arrWithObjectsWithArr = [{
name: 'Jon',
age: 32,
tags: ['driver', 'chef', 'jogger']
},
{
name: 'Elise',
age: 33,
tags: ['best chef', 'singer', 'dancer']
}
];
arrWithObjectsWithArr.forEach(({
name,
tags: [firstItemFromTags, ...restOfTags]
}) => {
console.log(name, firstItemFromTags, restOfTags);
});
Ближе всего к вашей идее будет использовать Array.forEach()
, который принимает функцию clojure, которая будет выполнена для каждого элемента массива.
myArray.forEach(
(item) => {
// do something
console.log(item);
}
);
Другим жизнеспособным способом было бы использовать Array.map()
, который работает одинаково, но также и mutates
каждый элемент и возвращает его так:
var myArray = [1, 2, 3];
myArray = myArray.map(
(item) => {
return item + 1;
}
);
console.log(myArray); // [2, 3, 4]
map
не изменяет элементы массива, потому что она возвращает новый массив с элементами этого нового, являющимися результатом применения функции к элементам старого массива.
Синтаксис лямбда обычно не работает в IE 10 или ниже.
Обычно я использую
[].forEach.call(arrayName,function(value,index){
console.log("value of the looped element" + value);
console.log("index of the looped element" + index);
});
If you are a jQuery Fan and already have a jQuery file running, you should reverse the positions of the index and value parameters
$("#ul>li").each(function(**index,value**){
console.log("value of the looped element" + value);
console.log("index of the looped element" + index);
});
Вы можете вызвать forEach Как это:
let Array = [1,3,2];
theArray.forEach((element)=>{
// use the element of the array
console.log(element)
}
элемент будет иметь значение каждого индекса от 0 до длины массива.
Вывод:
1
3
2
Explaination:
forEach находится в классе прототипов. вы также можете назвать это какArray.prototype.forEach(...);
прототип: https://hackernoon.com/prototypes-in-javascript-5bba2990e04b
Вы также можете изменить массив таким образом:
for(let i=0;i<theArray.length;i++){
console.log(i); //i will have the value of each index
}
При повторении массива мы часто можем достичь одной из следующих целей:
Мы хотим перебрать массив и создать новый массив:
Array.prototype.map
Мы хотим перебрать массив и не создавать новый массив:
Array.prototype.forEach
for..of
циклы
В JS существует множество способов достижения обеих этих целей. Однако некоторые из них более примитивны, чем другие. Ниже вы можете найти некоторые общепринятые методы (наиболее удобные imo) для выполнения итерации массива в javascript.
Map
map()
- это функция, расположенная на Array.prototype
которая может преобразовывать каждый элемент массива и затем возвращает новый массив. map()
принимает в качестве аргумента функцию обратного вызова и работает следующим образом:
let arr = [1, 2, 3, 4, 5];
let newArr = arr.map((element, index, array) => {
return element * 2;
})
console.log(arr);
console.log(newArr);
Обратный вызов, который мы передали в map()
в качестве аргумента, выполняется для каждого элемента. Затем возвращается массив, который имеет ту же длину, что и исходный массив. В этом новом элементе массива преобразуется функция обратного вызова, переданная в качестве аргумента map()
.
Четкое различие между механизмом map
и other loop, как forEach
и for..of
, что map
возвращается как новый массив и оставляет старый массив неповрежденным (за исключением случаев, когда вы просто манипулируете им с помощью мысли, как splice
).
Также обратите внимание, что обратный вызов функции map
предоставляет в качестве второго аргумента номер индекса текущей итерации. Кроме того, третий аргумент предоставляет массив, на который была вызвана map
. Иногда эти свойства могут быть очень полезными.
forEach
forEach
- это функция, которая находится на Array.prototype
которая принимает функцию обратного вызова в качестве аргумента. Затем он выполняет эту функцию обратного вызова для каждого элемента массива. В отличие от функции map()
функция forEach ничего не возвращает (undefined
). Например:
let arr = [1, 2, 3, 4, 5];
arr.forEach((element, index, array) => {
console.log(element * 2);
if (index === 4) {
console.log(array)
}
// index, and oldArray are provided as 2nd and 3th argument by the callback
})
console.log(arr);
Точно так же, как функция map
, обратный вызов forEach
предоставляет в качестве второго аргумента номер индекса текущей итерации. Также третий аргумент предоставляет массив, на который был вызван forEach
.
for..of
элементы, используя Цикл for..of
циклы через каждый элемент массива (или любой другой итерируемый объект). Он работает следующим образом:
let arr = [1, 2, 3, 4, 5];
for(let element of arr) {
console.log(element * 2);
}
В приведенном выше примере element
обозначает element
массива, а arr
- массив, который мы хотим создать. Не то, чтобы element
name был произвольным, и мы могли бы выбрать любое другое имя, например, "el" или что-то более декларативное, когда это применимо.
Не следует путать for..in
цикл с for..of
цикла. for..in
будет перебирать все перечислимые свойства массива, тогда как цикл for..of
будет только циклически проходить через элементы массива. Например:
let arr = [1, 2, 3, 4, 5];
arr.foo = 'foo';
for(let element of arr) {
console.log(element);
}
for(let element in arr) {
console.log(element);
}
Если у вас массивный массив, вы должны использовать iterators
чтобы получить некоторую эффективность. Итераторы являются свойством некоторых сборников JavaScript (таких как Map
, Set
, String
, Array
). Даже для for..of
использования iterator
под капотом.
Итераторы повышают эффективность, позволяя вам потреблять элементы в списке по одному, как если бы они были потоком. Что делает специальный итератор особенным, так это то, как он перемещается по коллекции. Другие циклы должны загружать всю коллекцию спереди, чтобы перебирать ее, тогда как итератору нужно знать только текущую позицию в коллекции.
Вы получаете доступ к текущему элементу, вызывая next
метод итераторов. Следующий метод вернет value
текущего элемента и boolean
чтобы указать, когда вы достигли конца коллекции. Ниже приведен пример создания итератора из массива.
Преобразуйте свой обычный массив в итератор, используя метод values()
следующим образом:
const myArr = [2,3,4]
let it = myArr.values();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Вы также можете преобразовать свой обычный массив в итератор с помощью Symbol.iterator
следующим образом:
const myArr = [2,3,4]
let it = myArr[Symbol.iterator]();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Вы также можете преобразовать свой обычный array
в iterator
следующим образом:
let myArr = [8, 10, 12];
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
};
};
var it = makeIterator(myArr);
console.log(it.next().value); // {value: 8, done: false}
console.log(it.next().value); // {value: 10, done: false}
console.log(it.next().value); // {value: 12, done: false}
console.log(it.next().value); // {value: undefined, done: true}
ПРИМЕЧАНИЕ.
iterable
по умолчанию не iterable
. Используйте для for..in
в этом случае, потому что вместо значений он работает с ключами. Вы можете прочитать больше о iteration protocol
здесь.
var a = ["car", "bus", "truck"]
a.forEach(function(item, index) {
console.log("Index" + index);
console.log("Element" + item);
})
Если вы хотите сохранить функциональность своего кода, используйте map:
theArray.map(instance => do_something);
Таким образом, вы создадите новый массив для будущей работы и пропустите любой нежелательный побочный эффект.
// Looping through arrays using foreach ES6 way
var data = new Array(1,2,3,4,5);
data.forEach((val,index) => {
console.log("index :",index); // index
console.log("value :", val); // value
});
Я пришел с питона, и я нашел этот путь намного яснее.
theArray - массив, экземпляр - элемент массива.
for(let instance of theArray)
{
console.log("The instance",instance);
}
или же
for( instance in theArray)
{
console.log("The instance",instance);
}
сравнить с:
theArray.forEach(function(instance) {
console.log(instance);
});
но в конце дня оба делают одно и то же
Если вы хотите использовать forEach()
, это будет выглядеть так -
theArray.forEach ( element => {
console.log(element);
});
Если вы хотите использовать for()
, это будет выглядеть как -
for(let idx = 0; idx < theArray.length; idx++){
let element = theArray[idx];
console.log(element);
}
function printList(callback) {
// do your printList work
console.log('printList is done');
callback();
}
function updateDB(callback) {
// do your updateDB work
console.log('updateDB is done');
callback()
}
function getDistanceWithLatLong(callback) {
// do your getDistanceWithLatLong work
console.log('getDistanceWithLatLong is done');
callback();
}
function runSearchInOrder(callback) {
getDistanceWithLatLong(function() {
updateDB(function() {
printList(callback);
});
});
}
runSearchInOrder(function(){console.log('finished')});
होगा выход getDistanceWithLatLong сделан обновлениеDB завершен печатьList завершено
forEach
а не толькоfor
. как уже говорилось, в C # это было немного по-другому, и это меня смутило :)