Как лучше всего делать циклы в JavaScript

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

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

Но, как здесь проверено (http://www.robertnyman.com/2008/04/11/javascript-loop-performance/), вероятно, следует записать так, чтобы длина вычислялась только один раз.

В jQuery есть .each, в который можно вставить функцию. Мне это нравится немного больше, потому что мне не нужно вводить массив дважды, как в приведенном выше решении.

Если бы JavaScript поддерживал макросы, было бы проще простого, но, к сожалению, это не так.

Так что вы, ребята, используете?

Очевидно, то, что вы подразумеваете под «лучшим», является «самым чистым», верно? Кто-то может сказать, что «лучший» способ - сделать это наиболее быстрым способом, и в этом случае ответ, вероятно, будет другим ...

Jason Bunting 11.10.2008 05:51

Да хорошо. Я выбрал слово «лучший», потому что мне нужно было одно решение для циклов, которое я мог бы использовать всегда, даже не задумываясь об этом. Таким образом, он не должен быть ужасно медленным при работе с элементами 100k, он не должен быть ужасно длинным, чтобы писать и т. д.

Anders Rune Jensen 11.10.2008 08:23
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
29
2
2 867
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Вы всегда можете использовать цикл while и заранее вычислить предел массива.

Var max = a.length-1;
var i = 0;

while(i <= max)
{
var element = a[i];
i++;
}

Извините за резкость, но я не понимаю, насколько это улучшение. Вы по-прежнему указываете массив дважды, и в вашем решении окружающая среда загрязнена двумя переменными, область действия которых не должна выходить за рамки конструкции цикла while.

Anders Rune Jensen 11.10.2008 05:29

В любом случае среда будет «загрязнена», учитывая, что в Javascript областью видимости переменной является включающая функция, а не блок, в котором она объявлена.

Jason Etheridge 11.10.2008 05:41

Проверяя его по ссылке, указанной в вопросе, он, по крайней мере, так же быстро, если не быстрее, чем любая из реализаций цикла for.

Kibbee 11.10.2008 06:06
Ответ принят как подходящий

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

function createIterator(x) {
    var i = 0;

     return function(){
       return x[i++];
    };
}

Затем использовать:

var iterator=createIterator(['a','b','c','d','e','f','g']);

iterator();

возвращает «а»;

iterator();

возвращает «b»;

и так далее.

Чтобы перебрать весь список и отобразить каждый элемент:

var current;

while(current=iterator())
{
    console.info(current);
}

Имейте в виду, что приведенное выше допустимо только для итерации списка, содержащего «не ложные» значения. Если этот массив содержал что-либо из:

  • 0
  • ложный
  • ""
  • нулевой
  • NaN

предыдущий цикл остановился бы на этом элементе, а не всегда на том, чего вы хотите / ожидаете.

Чтобы избежать этого использования:

var current;

while((current=iterator())!==undefined)
{
   console.info(current);
}

Да, я тоже думал об использовании итераторов. Они намного лучше инкапсулируют концепцию обхода чего-либо, чем простые циклы. Но как бы вы в своем примере распечатали все элементы в итераторе?

Anders Rune Jensen 11.10.2008 05:39

Красивая сладость закрытия. Ах, я люблю их.

Jason Bunting 11.10.2008 05:51

Как узнать, что вы достигли конца, если ваш итератор не имеет функции HasNext? Если вы просто продолжите вызывать «итератор» в своем примере, вы в конечном итоге получите индекс массива за допустимые пределы.

Kibbee 11.10.2008 05:54

Кибби, Андерс, я добавил простой пример того, как перебирать весь список до ответа.

Ash 11.10.2008 05:57

Извините, я немного привык к использованию языков, которые выдают исключения, когда вы пытаетесь получить доступ за конец массива, чтобы попытаться закодировать что-то, что полагается на тот факт, что JS не генерирует исключение, когда вы пытаетесь сделай это.

Kibbee 11.10.2008 06:14

Kibbee, не извиняйся, я должен был добавить этот пример раньше. Одна из самых важных вещей, которые нужно знать в Javascript, - это «ложные» значения (значения, которые оцениваются как ложные). Это: "", null, 0, NaN, false и, наконец, undefined. Итератор полагается на возвращаемое значение undefined.

Ash 11.10.2008 06:23

Если вам понравился этот ответ, вас могут заинтересовать bob.pythonmac.org/archives/2005/07/06/iteration-in-javascrip‌ t и Mochikit mochikit.com/doc/html/MochiKit/Iter.html

Jonny Buchanan 11.10.2008 08:13

Это довольно хакерское занятие. Мне нравится это!

Manuel Ferreria 07.01.2009 22:59

Добро пожаловать в мир медленного и запутанного. Эта идиома далеко распространена в мире JavaScript, поэтому у людей возникнут трудности с вашей кодовой базой, если вы решите ее использовать. Если у вас большие петли, этот подход также очень медленный. Вызов функций в JS обходится дорого.

Jani Hartikainen 21.01.2010 19:40

@Jani, добро пожаловать в мир новых идей! Этот ответ может помочь сделать идиому более распространенной. Кроме того, по моему опыту, производительность более чем приемлема для обычного повседневного использования, и в любом случае это в значительной степени зависит от того, на каком движке Javascript она запущена. Вызов функций может быть дорогостоящим, но не обслуживаемый Javascript стоит намного дороже!

Ash 21.01.2010 20:01

«Стандартный» шлейф вряд ли станет недостижимым. Однако я вижу, что вы поняли мою точку зрения;)

Jani Hartikainen 21.01.2010 23:05

Мне нравится сексуальное использование замыканий, хотя я не верю, что это «лучший способ» зациклить массив в Javascript. Стандартный цикл for с кешированной длиной по-прежнему остается самым быстрым и гибким способом ИМХО. Но для нормального повседневного дерьма это должно быть нормально, хорошая работа;)

mynameistechno 27.08.2011 03:35

Небольшое улучшение оригинала, чтобы вычислить размер массива только один раз:

for(var i = 0, len = a.length; i < len; i++){ var element = a[i]; }

Кроме того, я вижу много циклов for..in. Однако имейте в виду, что технически это не кошерно и вызовет проблемы, в частности, с Prototype:

for (i in a) { var element = a[i]; }

Циклы for..in используются для перебора свойств объекта, хотя они, кажется, работают для массивов, они также будут перебирать свойство 'length' или любое другое динамически добавляемое свойство. Вот почему это плохо работает с Prototype.

Vincent Robert 12.10.2008 20:02

второй пример i, вероятно, создает глобальную

ajax333221 24.05.2012 03:58

Просто сначала сохраните длину в переменной.

  var len = a.length;
  for (var i = 0; i < len; i++) {
    var element = a[i];
  }

Если у вас много элементов в массиве и скорость является проблемой, тогда вы хотите использовать цикл while, который повторяется от самого высокого до самого низкого.

  var i = a.length;
  while( --i >= 0 ) {
    var element = a[i];
    // do stuff with element
  }  

> = 0 не требуется, просто замените --i на i--

Paul Hargreaves 15.01.2010 20:59

Сам я не использую, но один из моих коллег использует такой стиль:

var myArray = [1,2,3,4];
for (var i = 0, item; item = myArray[i]; ++i) {
    alert(item);
}

как и ответ Эша, это вызовет проблемы, если в вашем массиве есть "ложные" значения. Чтобы избежать этой проблемы, измените его на (item = myArray[i]) != undefined.

Я знаю, что опаздываю на вечеринку, но я использую обратные петли для петель, которые не зависят от порядка.

Очень похоже на @Mr. Ондатра - но упрощая тест:

var i = a.length, element = null;
while (i--) {
  element = a[i];
}

ну, я очень опаздываю на вечеринку, но это правильный ответ, и его следует принять как таковой. Для непосвященных предложение i-- сохраняет сравнение (потому что 0 = false в тестах JS). Предостережение 1: обратный порядок! Предостережение 2: читабельность невысока. Предостережение 3: кешированный цикл for почти так же хорош

annakata 07.01.2009 23:45

Итак, сначала вы определите идеальный цикл javascript, я считаю, что он должен выглядеть так:

ary.each (функция () {$ arguments [0]). remove ();})

Для этого может потребоваться библиотека prototype.js.

Затем вы получите отвращение к части arguments [0] и получите код автоматически из вашей серверной среды. Это работает, только если лестница - приморская.

Теперь у вас есть указанное выше, сгенерированное:

и делаю: [: каждый | каждый элемент удалить].

Это идет с автозавершением синтаксиса и точно соответствует приведенному выше javascript. И это заставит кружиться голову людей, которые раньше не использовали интеграцию прототипов Seasides, когда они читают ваш код. Это тоже заставляет вас чувствовать себя круто. Не говоря уже о том, что вы можете получить здесь выгоду. Девушкам это нравится!

Я не понимаю, в чем проблема с использованием стандартного цикла for (;;). Небольшой тест

var x;
var a = [];
// filling array
var t0 = new Date().getTime();
for( var i = 0; i < 100000; i++ ) {
    a[i] = Math.floor( Math.random()*100000 );
}

// normal loop
var t1 = new Date().getTime();
for( var i = 0; i < 100000; i++ ) {
    x = a[i];
}

// using length
var t2 = new Date().getTime();
for( var i = 0; i < a.length; i++ ) {
    x = a[i];
}

// storing length (pollution - we now have a global l as well as an i )
var t3 = new Date().getTime();
for( var i = 0, l = a.length; i < l; i++ ) {
    x = a[i];
}

// for in
var t4 = new Date().getTime();
for( var i in a ) {
    x = a[i];
}

// checked for in
var t5 = new Date().getTime();
for( var i in a ) {
    if (a.hasOwnProperty(i)) {
        x = a[i];
    }
}

var t6 = new Date().getTime();
var msg = 'filling array: '+(t1-t0)+'ms\n'+
          'normal loop: '+(t2-t1)+'ms\n'+
          'using length: '+(t3-t2)+'ms\n'+
          'storing length: '+(t4-t3)+'ms\n'+
          'for in: '+(t5-t4)+'ms\n'+
          'checked for in: '+(t6-t5)+'ms';
console.info( msg );

приводит к:

filling array: 227ms
normal loop: 21ms
using length: 26ms
storing length: 24ms 
for in: 154ms
checked for in: 176ms

Итак: - поскольку in занимает больше всего времени, использование свойства length (которое является свойством и не требует вычисления) почти так же быстро, как его сохранение первым, что лишь на немного медленнее, чем использование целого числа.
AND a for () - это обычный способ перебора массива, который все ожидают и понимают.

Все они добавляют переменную в область, в которой они работают, - i - это общее имя для этого использования и поэтому не должно использоваться для других целей. Сохранение длины сначала добавляет еще одну переменную - l - в область видимости, что необязательно.

Другие вопросы по теме