Какой лучший способ циклически проходить через набор элементов в JavaScript?

javascript arrays loops elements

86646 просмотра

14 ответа

В прошлом и в большинстве моих текущих проектов я обычно использовал цикл for следующим образом:

var elements = document.getElementsByTagName('div');
for (var i=0; i<elements.length; i++) {
    doSomething(elements[i]);
}

Я слышал, что использование цикла "наоборот пока" быстрее, но у меня нет реального способа подтвердить это:

var elements = document.getElementsByTagName('div'), 
    length = elements.length;

while(length--) {
    doSomething(elements[length]);
}

Что считается наилучшей практикой, когда дело доходит до зацикливания элементов в JavaScript или любого другого массива в этом отношении?

Автор: James Источник Размещён: 17.05.2019 02:56

Ответы (14)


51 плюса

Вот хорошая форма цикла, который я часто использую. Вы создаете итеративную переменную из оператора for, и вам не нужно проверять свойство длины, которое может быть особенно дорогостоящим, особенно при итерации по NodeList. Однако вы должны быть осторожны , вы не можете использовать его, если любое из значений в массиве может быть «ложным» . На практике я использую его только при переборе массива объектов, который не содержит нулей (например, NodeList). Но я люблю его синтаксический сахар.

var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];

for (var i=0, item; item = list[i]; i++) {
  // Look no need to do list[i] in the body of the loop
  console.log("Looping: index ", i, "item" + item);
}

Обратите внимание, что это также может быть использовано для обратной петли (если ваш список не имеет ['-1']свойства)

var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];

for (var i = list.length - 1, item; item = list[i]; i--) {
  console.log("Looping: index ", i, "item", item);
}

ES6 Обновление

for...ofдает имя, но не индекс, доступный с ES6

for (let item of list) {
    console.log("Looping: index ", "Sorry!!!", "item" + item);
}
Автор: Juan Mendes Размещён: 06.01.2011 09:57

25 плюса

Обратите внимание, что в некоторых случаях вам нужно выполнить цикл в обратном порядке (но тогда вы также можете использовать i--).

Например, кто-то хотел использовать новую getElementsByClassNameфункцию для зацикливания элементов данного класса и изменения этого класса. Он обнаружил, что только один из двух элементов был изменен (в FF3).
Это потому, что функция возвращает живой NodeList, который, таким образом, отражает изменения в дереве Dom. Прогулка по списку в обратном порядке позволила избежать этой проблемы.

var menus = document.getElementsByClassName("style2");
for (var i = menus.length - 1; i >= 0; i--)
{
  menus[i].className = "style1";
}

При увеличении прогрессии индекса, когда мы запрашиваем индекс 1, FF проверяет Dom и пропускает первый элемент с style2, который является 2-м из исходного Dom, таким образом, он возвращает 3-й начальный элемент!

Автор: PhiLho Размещён: 01.10.2008 12:23

9 плюса

Мне нравится делать:

 
var menu = document.getElementsByTagName('div');
for (var i = 0; menu[i]; i++) {
     ...
}

На каждой итерации нет вызова длины массива.

Автор: Размещён: 01.10.2008 01:04

7 плюса

На риск крича, я бы получил вспомогательную библиотеку javascript, такую ​​как jquery или прототип, которая инкапсулирует логику в хорошие методы - у обоих есть метод / итератор .each, чтобы сделать это - и они оба стремятся сделать это кросс-браузерно-совместимым

РЕДАКТИРОВАТЬ: Этот ответ был опубликован в 2008 году. Сегодня существуют гораздо лучшие конструкции. Этот конкретный случай может быть решен с помощью .forEach.

Автор: Per Hornshøj-Schierbeck Размещён: 01.10.2008 11:59

6 плюса

Я думаю, что использование первой формы - это, вероятно, верный путь, поскольку, вероятно, это самая распространенная структура цикла в известной вселенной, и, поскольку я не верю, что обратный цикл экономит ваше время в реальности (все еще делая приращение / декремент и сравнение на каждой итерации).

Код, который узнаваем и читаем другим, безусловно, хорошая вещь.

Автор: Adam Bellaire Размещён: 01.10.2008 12:00

6 плюса

У меня была очень похожая проблема ранее с document.getElementsByClassName (). Я не знал, что такое нодлист в то время.

var elements = document.getElementsByTagName('div');
for (var i=0; i<elements.length; i++) {
    doSomething(elements[i]);
}

Моя проблема заключалась в том, что я ожидал, что элементы будут массивом, но это не так. Список узлов Document.getElementsByTagName () возвращает итерацию, но вы не можете вызывать методы array.prototype для него.

Однако вы можете заполнить массив элементами списка узлов следующим образом:

var myElements = [];
for (var i=0; i<myNodeList.length; i++) {                               
    var element = myNodeList[i];
    myElements.push(element);
};

После этого вы можете свободно вызывать .innerHTML или .style или что-то еще для элементов вашего массива.

Автор: Chris Impicciche Размещён: 16.03.2016 01:05

4 плюса

Я тоже советую использовать простой способ (KISS! -)

- но можно найти некоторую оптимизацию, а именно, чтобы не проверять длину массива более одного раза:

var elements = document.getElementsByTagName('div');
for (var i=0, im=elements.length; im>i; i++) {
    doSomething(elements[i]);
}
Автор: roenving Размещён: 01.10.2008 12:08

4 плюса

Также см. Мой комментарий к тесту Эндрю Хеджеса ...

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

И, увы, неудивительно, что три протестированных мною браузера показали очень разные результаты, хотя оптимизированная простая итерация была самой быстрой во всех! -)

Тестовое задание:

Массив с 500 000 элементов строится вне реального теста, для каждой итерации выявляется значение определенного элемента массива.

Тестовый прогон 10 раз.

IE6:

Результаты:

Просто: 984 922 937 984 891 907 906 891 906 906

Среднее значение: 923,40 мс.

Оптимизировано: 766 766 844 797 750 750 750 765 765 766 766

Среднее: 773,50 мс.

Обратное делать / пока: 3375,1328,1516,1344,1375,1406,1688,1344,1297,1265

Среднее: 1593,80 мс. (Обратите внимание на один особенно неловкий результат)

Опера 9.52:

Результаты:

Простой: 344 343 344 359 353 359 344 359 359 359

Среднее: 351,30 мс.

Оптимизировано: 281 297 297 297 297 281 281 297 281 281

Среднее: 289,00 мс

Обратное делать / пока: 391 407 391 391 500 407 407 406 406 406

Среднее: 411,20 мс.

FireFox 3.0.1:

Результаты:

Просто: 278,251,259,245,243,242,259,246,247,256

Среднее: 252,60 мс.

Оптимизировано: 267,222,223,226,223,230,221,231,224,230

Среднее: 229,70 мс.

Обратное делать / пока: 414 381 389 383 388 389 381 387 400 379

Среднее: 389,10 мс.

Автор: roenving Размещён: 02.10.2008 10:22

3 плюса

Форма цикла, предоставленная Хуаном Мендесом , очень полезна и практична, я немного ее изменил, чтобы теперь она работала со строками false, null, zero и empty.

var items = [
    true,
    false,
    null,
    0,
    ""
];

for(var i = 0, item; (item = items[i]) !== undefined; i++)
{
    console.log("Index: " + i + "; Value: " + item);
}
Автор: Tornike Comaia Размещён: 04.01.2015 07:53

1 плюс

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

Автор: Georgi Размещён: 01.10.2008 12:02

0 плюса

Я предпочитаю цикл for, так как он более читабелен. Цикл от длины до 0 будет более эффективным, чем цикл от 0 до длины. И использование обратного цикла while более эффективно, чем цикл foor, как вы сказали. У меня больше нет ссылки на страницу с результатами сравнения, но я помню, что разница в разных браузерах различалась. Для некоторых браузеров обратный цикл while был в два раза быстрее. Однако это не имеет значения, если вы зацикливаете «маленькие» массивы. В вашем примере длина элементов будет «мала»

Автор: Gene Размещён: 01.10.2008 12:12

0 плюса

Я думаю, у вас есть две альтернативы. Для элементов dom, таких как jQuery и подобных фреймворков, вы найдете хороший метод итерации. Второй подход - цикл for.

Автор: David Robbins Размещён: 02.10.2008 10:32

-1 плюса

Мне нравится использовать TreeWalker, если набор элементов является дочерним для корневого узла.

Автор: GijsjanB Размещён: 07.10.2014 08:53

-1 плюса

Я знаю, что этот вопрос старый, но вот еще одно, чрезвычайно простое решение ...

var elements = Array.from(document.querySelectorAll("div"));

Тогда его можно использовать как любой стандартный массив.

Автор: Dustin Halstead Размещён: 12.03.2018 07:55
Вопросы из категории :
32x32