HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>В этой статье мы рассмотрим три основных способа перебора элементов настоящего массива. Кроме того, посмотрим, как выполнять перебор массивоподобных объектов в JavaScript.</p>
1 <p>В этой статье мы рассмотрим три основных способа перебора элементов настоящего массива. Кроме того, посмотрим, как выполнять перебор массивоподобных объектов в JavaScript.</p>
2 <h2>А. Перебор настоящих массивов</h2>
2 <h2>А. Перебор настоящих массивов</h2>
3 <p>Для этого используются: 1. Известный метод Array.prototype.forEach. 2. Классический цикл for. 3. "Правильно" построенный цикл for...in.</p>
3 <p>Для этого используются: 1. Известный метод Array.prototype.forEach. 2. Классический цикл for. 3. "Правильно" построенный цикл for...in.</p>
4 <p>Что же, давайте рассмотрим эти методы подробнее.</p>
4 <p>Что же, давайте рассмотрим эти методы подробнее.</p>
5 <h3>1. Метод forEach</h3>
5 <h3>1. Метод forEach</h3>
6 <p>Пример использования:</p>
6 <p>Пример использования:</p>
7 var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); });<p>Достоинства forEach заключаются в том, что вам не надо объявлять локальные переменные, чтобы хранить индекс и значения текущего элемента массива, так как они автоматически передаются в функцию обратного вызова (так называемый колбэк) в качестве аргументов.</p>
7 var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); });<p>Достоинства forEach заключаются в том, что вам не надо объявлять локальные переменные, чтобы хранить индекс и значения текущего элемента массива, так как они автоматически передаются в функцию обратного вызова (так называемый колбэк) в качестве аргументов.</p>
8 <p>С помощью forEach вы не только сможете выполнить перебор всех элементов массива, но и получите возможность выполнения некоторых действий с массивами: 1)<strong>some</strong>- возвращает true, когда хотя бы для одного элемента массива колбэк возвращает значение, приводимое к true; 2)<strong>every</strong>- возвращает true, когда для каждого элемента массива колбэк возвращает значение, приводимое к true; 3)<strong>filter</strong>- обеспечивает создание нового массива, включающего те элементы исходного, для коих колбэк возвращает true; 4)<strong>reduce</strong>- сводит массив к единственному значению, т. е. колбэк применяется по очереди к каждому элементу массива, начиная с 1-го (полезно при вычислении суммы элементов массива и прочих итоговых функций); 5)<strong>map</strong>- обеспечивает создание нового массива, состоящего из значений, которые возвращаются колбэком; 6)<strong>reduceRight</strong>- работает так же, как и reduce с той лишь разницей, что перебирает элементы в обратном порядке.</p>
8 <p>С помощью forEach вы не только сможете выполнить перебор всех элементов массива, но и получите возможность выполнения некоторых действий с массивами: 1)<strong>some</strong>- возвращает true, когда хотя бы для одного элемента массива колбэк возвращает значение, приводимое к true; 2)<strong>every</strong>- возвращает true, когда для каждого элемента массива колбэк возвращает значение, приводимое к true; 3)<strong>filter</strong>- обеспечивает создание нового массива, включающего те элементы исходного, для коих колбэк возвращает true; 4)<strong>reduce</strong>- сводит массив к единственному значению, т. е. колбэк применяется по очереди к каждому элементу массива, начиная с 1-го (полезно при вычислении суммы элементов массива и прочих итоговых функций); 5)<strong>map</strong>- обеспечивает создание нового массива, состоящего из значений, которые возвращаются колбэком; 6)<strong>reduceRight</strong>- работает так же, как и reduce с той лишь разницей, что перебирает элементы в обратном порядке.</p>
9 <h3>2. Цикл for</h3>
9 <h3>2. Цикл for</h3>
10 <p>Что тут скажешь - старый добрый for…</p>
10 <p>Что тут скажешь - старый добрый for…</p>
11 var a = ["a", "b", "c"]; var index; for (index = 0; index &lt; a.length; ++index) { console.log(a[index]); }<p>Кстати, когда длина массива неизменна в течение цикла, а цикл принадлежит критическому с точки зрения производительности участку кода (что маловероятно), подходит "более оптимальная" версия for с хранением длины массива:</p>
11 var a = ["a", "b", "c"]; var index; for (index = 0; index &lt; a.length; ++index) { console.log(a[index]); }<p>Кстати, когда длина массива неизменна в течение цикла, а цикл принадлежит критическому с точки зрения производительности участку кода (что маловероятно), подходит "более оптимальная" версия for с хранением длины массива:</p>
12 var a = ["a", "b", "c"]; var index, len; for (index = 0, len = a.length; index &lt; len; ++index) { console.log(a[index]); }<p>По идее, данный код должен выполняться немного быстрее предыдущего.</p>
12 var a = ["a", "b", "c"]; var index, len; for (index = 0, len = a.length; index &lt; len; ++index) { console.log(a[index]); }<p>По идее, данный код должен выполняться немного быстрее предыдущего.</p>
13 <p>Если же порядок перебора элементов не особо важен, можно выполнить очередную оптимизацию, избавившись от переменной хранения длины массива и изменив прямой порядок перебора на обратный:</p>
13 <p>Если же порядок перебора элементов не особо важен, можно выполнить очередную оптимизацию, избавившись от переменной хранения длины массива и изменив прямой порядок перебора на обратный:</p>
14 var a = ["a", "b", "c"]; var index; for (index = a.length - 1; index &gt;= 0; --index) { console.log(a[index]); }<p>Однако справедливости ради стоит отметить, что в современных движках JavaScript вышеописанные игры с оптимизацией мало что значат.</p>
14 var a = ["a", "b", "c"]; var index; for (index = a.length - 1; index &gt;= 0; --index) { console.log(a[index]); }<p>Однако справедливости ради стоит отметить, что в современных движках JavaScript вышеописанные игры с оптимизацией мало что значат.</p>
15 <h3>3. Правильное использование цикла for...in</h3>
15 <h3>3. Правильное использование цикла for...in</h3>
16 <p>Вообще, цикл for...in не предназначен для перебора массивов. Он перебирает не индексы нашего массива, а перечисляемые свойства объекта.</p>
16 <p>Вообще, цикл for...in не предназначен для перебора массивов. Он перебирает не индексы нашего массива, а перечисляемые свойства объекта.</p>
17 <p>Однако, если нам нужен перебор<a>разреженных массивов</a>, цикл for...in может быть весьма полезным, если, разумеется, соблюдать меры предосторожности:</p>
17 <p>Однако, если нам нужен перебор<a>разреженных массивов</a>, цикл for...in может быть весьма полезным, если, разумеется, соблюдать меры предосторожности:</p>
18 // a - разреженный массив var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (var key in a) { if (a.hasOwnProperty(key) &amp;&amp; /^0$|^[1-9]\d*$/.test(key) &amp;&amp; key &lt;= 4294967294) { console.log(a[key]); } }<p>В вышеописанном примере на каждой циклической итерации осуществляются 2 проверки: 1) то, что массив имеет своё свойство с именем key (ненаследованное из его прототипа); 2) то, что key - это строка, содержащая десятичную запись целого числа, значение которого менее 4294967294.</p>
18 // a - разреженный массив var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (var key in a) { if (a.hasOwnProperty(key) &amp;&amp; /^0$|^[1-9]\d*$/.test(key) &amp;&amp; key &lt;= 4294967294) { console.log(a[key]); } }<p>В вышеописанном примере на каждой циклической итерации осуществляются 2 проверки: 1) то, что массив имеет своё свойство с именем key (ненаследованное из его прототипа); 2) то, что key - это строка, содержащая десятичную запись целого числа, значение которого менее 4294967294.</p>
19 <p>Да, такие проверки могут отнять много времени, но если мы имеем дело с разреженным массивом, данный способ эффективнее обычного цикла for, т. к. в последнем случае перебираются лишь элементы, которые определены в массиве явно. Например в коде выше произойдёт всего 3 итерации (для индексов 0, 10 и 10000), в то время как при использовании классического for - 10001 итерация.</p>
19 <p>Да, такие проверки могут отнять много времени, но если мы имеем дело с разреженным массивом, данный способ эффективнее обычного цикла for, т. к. в последнем случае перебираются лишь элементы, которые определены в массиве явно. Например в коде выше произойдёт всего 3 итерации (для индексов 0, 10 и 10000), в то время как при использовании классического for - 10001 итерация.</p>
20 <p>Кстати, код проверок можете оформить в виде отдельной функции:</p>
20 <p>Кстати, код проверок можете оформить в виде отдельной функции:</p>
21 function arrayHasOwnIndex(array, key) { return array.hasOwnProperty(key) &amp;&amp; /^0$|^[1-9]\d*$/.test(key) &amp;&amp; key &lt;= 4294967294; }<p>В таком случае тело цикла существенно сократится:</p>
21 function arrayHasOwnIndex(array, key) { return array.hasOwnProperty(key) &amp;&amp; /^0$|^[1-9]\d*$/.test(key) &amp;&amp; key &lt;= 4294967294; }<p>В таком случае тело цикла существенно сократится:</p>
22 for (key in a) { if (arrayHasOwnIndex(a, key)) { console.log(a[key]); } }<p>Вышеописанный код универсален, но вы можете использовать версию и короче. Формально она не совсем правильна, зато подходит практически для любых случаев:</p>
22 for (key in a) { if (arrayHasOwnIndex(a, key)) { console.log(a[key]); } }<p>Вышеописанный код универсален, но вы можете использовать версию и короче. Формально она не совсем правильна, зато подходит практически для любых случаев:</p>
23 for (key in a) { if (a.hasOwnProperty(key) &amp;&amp; String(parseInt(key, 10)) === key) { console.log(a[key]); } }<h2>Б. Перебор массивоподобных объектов</h2>
23 for (key in a) { if (a.hasOwnProperty(key) &amp;&amp; String(parseInt(key, 10)) === key) { console.log(a[key]); } }<h2>Б. Перебор массивоподобных объектов</h2>
24 <p>В JavaScript есть не только настоящие массивы, но и массивоподобные объекты. У них есть свойство length и свойства с именами в виде чисел, которые соответствуют элементам массива. Это DOM-коллекции NodeList либо псевдомассив arguments, доступный внутри любого метода/функции.</p>
24 <p>В JavaScript есть не только настоящие массивы, но и массивоподобные объекты. У них есть свойство length и свойства с именами в виде чисел, которые соответствуют элементам массива. Это DOM-коллекции NodeList либо псевдомассив arguments, доступный внутри любого метода/функции.</p>
25 <h3>1. Применяем способы перебора настоящих массивов</h3>
25 <h3>1. Применяем способы перебора настоящих массивов</h3>
26 <p>Практически все способы перебора настоящих массивов можно применять для перебора массивоподобных объектов. Например, при использовании конструкций for и for...in всё делается тем же путём.</p>
26 <p>Практически все способы перебора настоящих массивов можно применять для перебора массивоподобных объектов. Например, при использовании конструкций for и for...in всё делается тем же путём.</p>
27 <p>Что касается forEach и прочих методов Array.prototype, то тут надо использовать вызов Function.apply.или Function.call.</p>
27 <p>Что касается forEach и прочих методов Array.prototype, то тут надо использовать вызов Function.apply.или Function.call.</p>
28 <p>Допустим, вы желаете применить forEach к свойству childNodes объекта Node:</p>
28 <p>Допустим, вы желаете применить forEach к свойству childNodes объекта Node:</p>
29 Array.prototype.forEach.call(node.childNodes, function(child) { // делаем что-либо с объектом child });<p>Чтобы было удобнее повторно использовать этот приём, объявите ссылку на метод Array.prototype.forEach в отдельной переменной и используйте её как сокращение:</p>
29 Array.prototype.forEach.call(node.childNodes, function(child) { // делаем что-либо с объектом child });<p>Чтобы было удобнее повторно использовать этот приём, объявите ссылку на метод Array.prototype.forEach в отдельной переменной и используйте её как сокращение:</p>
30 // (Считаем, что весь код ниже находится в одной области видимости) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) { // делаем что-либо с объектом child });<p>Когда в массивоподобном объекте есть итератор, его можно задействовать явно либо неявно для перебора объекта тем же способом, как и в случае с настоящими массивами.</p>
30 // (Считаем, что весь код ниже находится в одной области видимости) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) { // делаем что-либо с объектом child });<p>Когда в массивоподобном объекте есть итератор, его можно задействовать явно либо неявно для перебора объекта тем же способом, как и в случае с настоящими массивами.</p>
31 <h3>2. Преобразование массивоподобного объекта в настоящий массив</h3>
31 <h3>2. Преобразование массивоподобного объекта в настоящий массив</h3>
32 <p>Простой способ перебора - преобразовать массивоподобный объект в настоящий массив. Для этого подходит, универсальный метод Array.prototype.slice:</p>
32 <p>Простой способ перебора - преобразовать массивоподобный объект в настоящий массив. Для этого подходит, универсальный метод Array.prototype.slice:</p>
33 var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);<p>Если же желаете преобразовать коллекцию NodeList в настоящий массив, то лучше действовать несколько иначе:</p>
33 var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);<p>Если же желаете преобразовать коллекцию NodeList в настоящий массив, то лучше действовать несколько иначе:</p>
34 var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);<p>Кроме того, вместо Array.prototype.slice можно использовать и Array.from.</p>
34 var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);<p>Кроме того, вместо Array.prototype.slice можно использовать и Array.from.</p>
35 <p><em>На этом всё, удачного вам кодинга!</em></p>
35 <p><em>На этом всё, удачного вам кодинга!</em></p>
36 <p><a>Источник</a></p>
36 <p><a>Источник</a></p>
37  
37