Перебрать массив в JavaScript

2675

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

String[] myStringArray = {"Hello", "World"};
for (String s : myStringArray)
{
    // Do something
}

Можете ли вы сделать то же самое в JavaScript?

  • 5
    Итак, я немного запутался, можно ли использовать расширенный цикл for при доступе к объектам? И использовать последовательный для заполнения одного? Это правильно?
  • 38
    нет, это действительно просто, объекты массива имеют числовые индексы, поэтому вы хотите перебирать эти индексы в числовом порядке, последовательный цикл гарантирует, что улучшенный цикл for-in перечисляет свойства объекта без определенного порядка, а также перечисляет унаследованные свойства ... для перебора массивов всегда рекомендуются последовательные циклы ...
Показать ещё 6 комментариев
Теги:
arrays
for-loop
loops

39 ответов

3130

Используйте последовательный цикл for:

var myStringArray = ["Hello","World"];
    var arrayLength = myStringArray.length;
    for (var i = 0; i < arrayLength; i++) {
        console.log(myStringArray[i]);
        //Do something
    }

@zipcodeman предлагает использовать оператор for...in, но для итерации массивов for-in следует избегать, этот оператор предназначен для перечисления свойств объекта.

Он не должен использоваться для объектов, подобных массиву, потому что:

  • Порядок итерации не гарантируется, индексы массива могут не посещаться в числовом порядке.
  • Унаследованные свойства также перечислены.

Второй момент заключается в том, что это может создать много проблем, например, если вы расширите объект Array.prototype туда метод, это свойство также будет перечислено.

Например:

Array.prototype.foo = "foo!";
    var array = ['a', 'b', 'c'];
    
    for (var i in array) {
      console.log(array[i]);
    }

Приведенный выше код будет утешать "a", "b", "c" и "foo!".

Это будет особенно проблематично, если вы используете какую-то библиотеку, которая сильно зависит от расширения собственных прототипов (например, MooTools).

Оператор for-in как я уже говорил, предназначен для перечисления свойств объекта, например:

var obj = {
      "a": 1,
      "b": 2,
      "c": 3
    };

    for (var prop in obj) {
      if (obj.hasOwnProperty(prop)) { 
      // or if (Object.prototype.hasOwnProperty.call(obj,prop)) for safety...
        console.log("prop: " + prop + " value: " + obj[prop])
      }
    }

В приведенном выше примере метод hasOwnProperty позволяет перечислять только собственные свойства, то есть только те свойства, которые физически имеет объект, без унаследованных свойств.

Я бы порекомендовал вам прочитать следующую статью:

  • 16
    Это причина (по его собственным данным CMS) stackoverflow.com/questions/1885317/…
  • 0
    Ваш перечисляет undefined элементы, а for(in) нет. Официальный алгоритм foreach проверяет, if(in) . Я согласен с тем, что итерация только числовых индексов является правильной для перечисления элементов ( hasOwnProperty допускает нечисловые свойства), но обратите внимание, что это превосходный дизайн, не зависящий от порядка итерации, поэтому он позволяет включить параллелизм , предполагая, что повторный обратный вызов не имеет побочных эффекты
Показать ещё 14 комментариев
1068

Да, предполагается, что ваш реализации включает в себя for... of функции, введенной в ECMAScript 2015 (далее "Harmony" релиз)... который является довольно безопасным предположение в эти дни.

Это работает так:

// REQUIRES ECMASCRIPT 2015+
var s, myStringArray = ["Hello", "World"];
for (s of myStringArray) {
  // ... do something with s ...
}

Или, что еще лучше, поскольку ECMAScript 2015 также предоставляет переменные в области блока с помощью let и const:

// REQUIRES ECMASCRIPT 2015+
const myStringArray = ["Hello", "World"];
for (const s of myStringArray) {
  // ... do something with s ...
}
// s is no longer defined here

Примечание о разреженных массивах: массив в JavaScript может фактически не хранить столько элементов, сколько указано в его length; это сообщаемое число просто на единицу больше, чем самый высокий индекс, при котором хранится значение. Если массив содержит меньше элементов, чем указано в его длине, он называется разреженным. Например, вполне допустимо иметь массив с элементами только по индексам 3, 12 и 247; length такого массива указывается как 248, хотя на самом деле он хранит только 3 значения. Если вы попытаетесь получить доступ к элементу по любому другому индексу, у массива появится undefined значение. Поэтому, когда вы хотите "зациклить" массив, возникает вопрос: хотите ли вы зациклить весь диапазон, обозначенный его длиной, и обрабатывать undefined для каких-либо отсутствующих элементов, или вы хотите обрабатывать только те элементы, которые действительно присутствуют? Существует множество приложений для обоих подходов; это зависит только от того, для чего вы используете массив.

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

Конечно, некоторые разработчики не имеют иного выбора, кроме как использовать другой подход в любом случае, потому что по какой - то причине они ориентации версию JavaScript, который еще не поддерживается for... of.

Если ваша реализация JavaScript совместима с предыдущей версией спецификации ECMAScript (которая исключает, например, версии Internet Explorer до 9), тогда вы можете использовать метод итератора forEach вместо цикла. В этом случае вы передаете функцию, которая будет вызываться для каждого элемента в массиве:

var myStringArray = [ "Hello", "World" ];
myStringArray.forEach( function(s) { 
     // ... do something with s ...
} );

В отличие от for... of, forEach вызывает функцию только для элементов, которые на самом деле содержат значения. Если передать наш гипотетический массив с тремя элементами и длиной 248, он будет вызывать функцию только три раза, а не 248 раз. Он также различает отсутствующие элементы и элементы, которые на самом деле установлены как undefined; для последнего он по-прежнему будет вызывать функцию, передавая в качестве аргумента undefined значение. Если это, как вы хотите обрабатывать разреженные массивы, .forEach может быть путь, даже если ваш переводчик поддерживает for... of.

Последний вариант, который работает во всех версиях JavaScript, - это явный цикл подсчета. Вы просто считаете от 0 до единицы меньше длины и используете счетчик в качестве индекса. Основной цикл выглядит так:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  s = myStringArray[i];
  // ... do something with s ...
}

Одним из преимуществ этого подхода является то, что вы можете выбирать, как обрабатывать разреженные массивы; Приведенный выше код будет запускать тело цикла по полной length с s установленным на undefined для любых отсутствующих элементов, как for.. of. Если вместо этого вы хотите обрабатывать только реально существующие элементы разреженного массива, такие как .forEach, вы можете добавить in индекс простую проверку:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  if (i in myStringArray) {
    s = myStringArray[i];
    // ... do something with s ...
  }
}

Присвоение значения длины локальной переменной (в отличие от включения полного выражения myStringArray.length в условие цикла) может существенно myStringArray.length на производительность, поскольку оно пропускает поиск свойств каждый раз до конца; при использовании Rhino на моей машине ускорение составляет 43%.

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

var i, len, myStringArray = [ "Hello", "World" ];
for (len = myStringArray.length, i=0; i<len; ++i) {

Упомянутый другими синтаксис for... in используется для циклического обхода свойств объекта; так как массив в JavaScript - это просто объект с числовыми именами свойств (и автоматически обновляемым свойством length), вы можете теоретически зациклить массив с ним. Но проблема в том, что он не ограничивается числовыми значениями свойств (помните, что даже методы на самом деле являются просто свойствами, значение которых является замыканием), и при этом не гарантируется, что они будут перебирать их в числовом порядке. Следовательно, синтаксис for... in не должен использоваться для циклического перемещения по массивам.

  • 21
    Обратите внимание, что некоторые интерпретаторы (например, V8) автоматически кэшируют длину массива, если код вызывается достаточное количество раз, и обнаруживает, что длина не изменяется циклом. Хотя кэширование длины по-прежнему полезно, оно может не обеспечить повышение скорости, если ваш код вызывается достаточно много раз, чтобы реально изменить ситуацию.
  • 2
    @ mark-reed Не могли бы вы объяснить, почему вы использовали i in myStringArray в вашем примере? Как это может быть ложным?
Показать ещё 14 комментариев
437

Вы можете использовать map, которая представляет собой метод функционального программирования, который также доступен на других языках, таких как Python и Haskell.

[1,2,3,4].map( function(item) {
     alert(item);
})

Общий синтаксис:

array.map(func)

В общем случае func принимает один параметр, который является элементом массива. Но в случае JavaScript он может принимать второй параметр, который является индексом элемента, и третьим параметром, который является самим массивом.

Возвращаемое значение array.map - это другой массив, поэтому вы можете использовать его следующим образом:

var x = [1,2,3,4].map( function(item) {return item * 10;});

И теперь x - [10,20,30,40].

Вам не нужно писать функцию inline. Это может быть отдельная функция.

var item_processor = function(item) {
      // Do something complicated to an item
}

new_list = my_list.map(item_processor);

который будет своего рода эквивалентом:

 for (item in my_list) {item_processor(item);}

Кроме того, вы не получите new_list.

  • 7
    Нет, но это может быть более мощным. проверить это: joelonsoftware.com/items/2006/08/01.html
  • 91
    Этот конкретный пример, вероятно, лучше реализовать с помощью Array.forEach . map для создания нового массива.
Показать ещё 9 комментариев
104

В JavaScript не рекомендуется проходить через массив с циклом for-in, но лучше использовать цикл for, например:

for(var i=0, len=myArray.length; i < len; i++){}

Он также оптимизирован ( "кеширование" длины массива). Если вы хотите узнать больше, прочитайте мой пост по теме.

  • 2
    myArray.forEach (function (obj) {}); все еще лучший
  • 0
    небольшое улучшение: вы можете использовать ++i вместо i++
Показать ещё 4 комментария
101

для (var s myStringArray) {

(Непосредственно отвечая на ваш вопрос: теперь вы можете!)

Большинство других ответов верны, но они не упоминают (как написано), что ECMA Script 6   2015 привносит новый механизм для итерации, цикл for..of.

Этот новый синтаксис - самый изящный способ перебора массива в javascript (так как вам не нужен индекс итерации), но он пока еще не поддерживается браузерами.

В настоящее время он работает с Firefox 13+, Chrome 37+ и не работает с другими браузерами (см. совместимость браузеров ниже). К счастью, у нас есть компиляторы JS (такие как Babel), которые позволяют нам использовать функции следующего поколения сегодня.

Он также работает на Node (я тестировал его на версии 0.12.0).

Итерирование массива

// You could also use "let" instead of "var" for block scope.
for (var letter of ["a", "b", "c"]) { 
   console.log(letter); 
}

Итерирование массива объектов

var band = [
  {firstName : 'John', lastName: 'Lennon'}, 
  {firstName : 'Paul', lastName: 'McCartney'}
];

for(var member of band){
  console.log(member.firstName + ' ' + member.lastName); 
}

Итерация генератора:

(пример извлечен из https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)

function* fibonacci() { // a generator function
  let [prev, curr] = [1, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (let n of fibonacci()) {
  console.log(n);
  // truncate the sequence at 1000
  if (n >= 1000) {
    break;
  }
}

Таблица совместимости: http://kangax.github.io/es5-compat-table/es6/ # Для петель

Spec: http://wiki.ecmascript.org/doku.php?id=harmony:iterators

}

  • 0
    Если вы используете ES6, я бы предложил const s вместо var s
89

Opera, Safari, Firefox и Chrome теперь используют общий набор расширенных методов Array для оптимизации множества общих циклов.

Возможно, вам не нужны все из них, но они могут быть очень полезными или будут, если каждый браузер их поддерживает.

Mozilla Labs опубликовала алгоритмы, которые они и WebKit используют, так что вы можете добавить их сами.

фильтр возвращает массив элементов, удовлетворяющих определенному условию или тесту.

каждый возвращает true, если каждый элемент массива проходит тест.

some возвращает true, если кто-либо передает тест.

forEach запускает функцию для каждого элемента массива и ничего не возвращает.

map похожа на forEach, но возвращает массив результатов операции для каждого элемента.

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

Игнорируйте его, пока он вам не понадобится.

indexOf и lastIndexOf найдите нужную позицию первого или последнего элемента, который точно соответствует его аргументу.

(function(){
    var p, ap= Array.prototype, p2={
        filter: function(fun, scope){
            var L= this.length, A= [], i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        val= this[i];
                        if(fun.call(scope, val, i, this)){
                            A[A.length]= val;
                        }
                    }
                    ++i;
                }
            }
            return A;
        },
        every: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && !fun.call(scope, this[i], i, this))
                        return false;
                    ++i;
                }
                return true;
            }
            return null;
        },
        forEach: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
            }
            return this;
        },
        indexOf: function(what, i){
            i= i || 0;
            var L= this.length;
            while(i< L){
                if(this[i]=== what)
                    return i;
                ++i;
            }
            return -1;
        },
        lastIndexOf: function(what, i){
            var L= this.length;
            i= i || L-1;
            if(isNaN(i) || i>= L)
                i= L-1;
            else
                if(i< 0) i += L;
            while(i> -1){
                if(this[i]=== what)
                    return i;
                --i;
            }
            return -1;
        },
        map: function(fun, scope){
            var L= this.length, A= Array(this.length), i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        A[i]= fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
                return A;
            }
        },
        some: function(fun, scope){
            var i= 0, L= this.length;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && fun.call(scope, this[i], i, this))
                        return true;
                    ++i;
                }
                return false;
            }
        }
    }
    for(p in p2){
        if(!ap[p])
            ap[p]= p2[p];
    }
    return true;
})();
  • 1
    Дополнение: IE поддерживает forEach начиная с версии 9, см. ForEach Метод MSDN
62

Используйте цикл while...

var i=0, item, items = ['one','two','three'];
while(item = items[i++]){
    console.log(item);
}

logs: 'one', 'two', 'three'

И для обратного порядка еще более эффективный цикл

var items = ['one','two','three'], i = items.length;
while(i--){
    console.log(items[i]);
}

logs: 'three', 'two', 'one'

Или классический цикл for

var items = ['one','two','three']
for(var i=0, l = items.length; i < l; i++){
    console.log(items[i]);
}

logs: 'one', 'two', 'three'

Ссылка: http://www.sitepoint.com/google-closure-how-not-to-write-javascript/

Показать ещё 2 комментария
53

вступление

С моего времени в колледже я программировал на Java, JavaScript, Pascal, ABAP, PHP, Progress 4GL, C/C++ и, возможно, на нескольких других языках, о которых я не могу сейчас думать.

В то время как все они имеют свои лингвистические особенности, каждый из этих языков разделяет многие из тех же основных понятий. Такие понятия включают процедуры/функции, IF -statements, FOR -loops и WHILE -loops.


Традиционный for -loop

Традиционный for цикла состоит из трех компонентов:

  1. Инициализация: выполняется до того, как блок look будет выполнен в первый раз
  2. Условие: проверяет условие каждый раз до того, как выполняется цикл цикла, и завершает цикл, если false
  3. Последующая мысль: выполняется каждый раз после выполнения цикла

Эти три компонента отделены друг от друга a ; символ. Содержимое для каждого из этих трех компонентов является необязательным, что означает, что for минимального цикла возможно следующее:

for (;;) {
    // Do stuff
}

Конечно, вам нужно будет включить if(condition === true) { break; } if(condition === true) { break; } или if(condition === true) { return; } if(condition === true) { return; } где-то внутри, for -loop, чтобы остановить его.

Обычно, однако, инициализация используется для объявления индекса, это условие используется для сравнения этого индекса с минимальным или максимальным значением, а последующая мысль используется для увеличения индекса:

for (var i = 0, length = 10; i < length; i++) {
    console.log(i);
}

Использование традиционного for циклы к петле через массив

Традиционный способ перебора массива состоит в следующем:

for (var i = 0, length = myArray.length; i < length; i++) {
    console.log(myArray[i]);
}

Или, если вы предпочитаете зацикливать назад, вы делаете это:

for (var i = myArray.length - 1; i > -1; i--) {
    console.log(myArray[i]);
}

Однако существует множество вариантов, например, таких как:

for (var key = 0, value = myArray[key], length = myArray.length; key < length; value = myArray[++key]) {
    console.log(value);
}

... или этот...

var i = 0, length = myArray.length;
for (; i < length;) {
    console.log(myArray[i]);
    i++;
}

... или этот:

var key = 0, value;
for (; value = myArray[key++];){
    console.log(value);
}

Что лучше всего работает, в значительной степени зависит как от личного вкуса, так и от конкретного варианта использования, который вы реализуете.

Обратите внимание, что каждый из этих вариантов поддерживается всеми браузерами, в том числе очень старыми!


В while цикл

Одна альтернатива for цикла является while цикл. Чтобы перебрать массив, вы можете сделать это:

var key = 0;
while(value = myArray[key++]){
    console.log(value);
}

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

Также обратите внимание, что цикл while может быть переписан как цикл for. Например, в while петля ведет себя здесь выше точно так же, как это for -loop:

for(var key = 0; value = myArray[key++];){
    console.log(value);
}

For...in и for...of

В JavaScript вы также можете сделать это:

for (i in myArray) {
    console.log(myArray[i]);
}

Однако это следует использовать с осторожностью, поскольку во всех случаях оно не ведет себя так же, как традиционный for цикла, и есть потенциальные побочные эффекты, которые необходимо учитывать. См. Почему используется "для... в" с итерацией массива плохая идея? Больше подробностей.

В качестве альтернативы for...in, там теперь тоже for...of Следующий пример показывает разницу между for...of цикла, и for...in цикле:

var myArray = [3, 5, 7];
myArray.foo = "hello";

for (var i in myArray) {
  console.log(i); // logs 0, 1, 2, "foo"
}

for (var i of myArray) {
  console.log(i); // logs 3, 5, 7
}

Кроме того, вам нужно учитывать, что ни одна версия Internet Explorer не поддерживает for...of ( Edge 12+ делает), а for...in требуется хотя бы Internet Explorer 10.


Array.prototype.forEach()

Альтернативой for -loops является Array.prototype.forEach(), который использует следующий синтаксис:

myArray.forEach(function(value, key, myArray) {
    console.log(value);
});

Array.prototype.forEach() поддерживается всеми современными браузерами, а также Internet Explorer 9 и более поздними Array.prototype.forEach().


Библиотеки

Наконец, многие библиотеки утилиты также имеют свои собственные изменения foreach. AFAIK, три самых популярных из них:

jQuery.each(), в jQuery:

$.each(myArray, function(key, value) {
    console.log(value);
});

_.each(), в Underscore.js:

_.each(myArray, function(value, key, myArray) {
    console.log(value);
});

_.forEach(), в Lodash.js:

_.forEach(myArray, function(value, key) {
    console.log(value);
});
37

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

for (var i=myArray.length;i--;){
  var item=myArray[i];
}

Это имеет преимущество кэширования длины (похоже на for (var i=0, len=myArray.length; i<len; ++i) и в отличие от for (var i=0; i<myArray.length; ++i)), в то время как количество символов меньше.

Есть даже несколько раз, когда вы должны перебирать обратное, например, при повторении live NodeList, где вы планируете удалять элементы из DOM во время итерации.

  • 16
    Для людей, которые не понимают, что такого гениального: сначала вычисляется выражение i-- и позволяет циклу продолжаться, когда он не ложный ... Затем счетчик уменьшается. Как только я стану равным нулю, он выйдет из цикла, так как ноль - ложное значение в Javascript.
  • 5
    falsish? Вы имеете в виду фальси. Давайте все придерживаться правильной терминологии, чтобы избежать путаницы;)
Показать ещё 4 комментария
27

Некоторые случаи использования циклического перебора массива функциональным способом программирования в JavaScript:

1. Просто перебрать массив

const myArray = [{x:100}, {x:200}, {x:300}];

myArray.forEach((element, index, array) => {
    console.log(element.x); // 100, 200, 300
    console.log(index); // 0, 1, 2
    console.log(array); // same myArray object 3 times
});

Примечание: Array.prototype.forEach(), строго говоря, не является функциональным способом, так как функция, которую он принимает в качестве входного параметра, не должна возвращать значение, которое, таким образом, не может рассматриваться как чистая функция.

2. Проверьте, проходит ли какой-либо из элементов массива тест

const people = [
    {name: 'John', age: 23}, 
    {name: 'Andrew', age: 3}, 
    {name: 'Peter', age: 8}, 
    {name: 'Hanna', age: 14}, 
    {name: 'Adam', age: 37}];

const anyAdult = people.some(person => person.age >= 18);
console.log(anyAdult); // true

3. Преобразовать в новый массив

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray= myArray.map(element => element.x);
console.log(newArray); // [100, 200, 300]

Примечание. Метод map() создает новый массив с результатами вызова предоставленной функции для каждого элемента в вызывающем массиве.

4. Подведите итог определенного свойства и рассчитайте его среднее

const myArray = [{x:100}, {x:200}, {x:300}];

const sum = myArray.map(element => element.x).reduce((a, b) => a + b, 0);
console.log(sum); // 600 = 0 + 100 + 200 + 300

const average = sum / myArray.length;
console.log(average); // 200

5. Создайте новый массив на основе оригинала, но не изменяя его

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray= myArray.map(element => {
    return {
        ...element,
        x: element.x * 2
    };
});

console.log(myArray); // [100, 200, 300]
console.log(newArray); // [200, 400, 600]

6. Подсчитайте количество каждой категории

const people = [
    {name: 'John', group: 'A'}, 
    {name: 'Andrew', group: 'C'}, 
    {name: 'Peter', group: 'A'}, 
    {name: 'James', group: 'B'}, 
    {name: 'Hanna', group: 'A'}, 
    {name: 'Adam', group: 'B'}];

const groupInfo = people.reduce((groups, person) => {
    const {A = 0, B = 0, C = 0} = groups;
    if (person.group === 'A') {
        return {...groups, A: A + 1};
    } else if (person.group === 'B') {
        return {...groups, B: B + 1};
    } else {
        return {...groups, C: C + 1};
    }
}, {});

console.log(groupInfo); // {A: 3, C: 1, B: 2}

7. Получить подмножество массива на основе определенных критериев

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray = myArray.filter(element => element.x > 250);
console.log(newArray); // [{x:300}] 

Примечание. Метод filter() создает новый массив со всеми элементами, которые проходят тест, реализованный предоставленной функцией.

8. Сортировать массив

const people = [
  { name: "John", age: 21 },
  { name: "Peter", age: 31 },
  { name: "Andrew", age: 29 },
  { name: "Thomas", age: 25 }
];

let sortByAge = people.sort(function (p1, p2) {
  return p1.age - p2.age;
});

console.log(sortByAge);

Изображение 2019

9. Найти элемент в массиве

const people = [ {name: "john", age:23},
                {name: "john", age:43},
                {name: "jim", age:101},
                {name: "bob", age:67} ];

const john = people.find(person => person.name === 'john');
console.log(john);

Изображение 2020

Метод Array.prototype.find() возвращает значение первого элемента в массиве, которое удовлетворяет предоставленной функции тестирования.

Рекомендации

27

Существует несколько способов циклического преобразования массива в JavaScript.

Общий цикл:

var i;
for (i = 0; i < substr.length; ++i) {
    // Do something with `substr[i]`
}

ES5 для каждого:

substr.forEach(function(item) {
    // Do something with `item`
});

jQuery.each:

jQuery.each(substr, function(index, item) {
    // Do something with `item` (or `this` is also `item` if you like)
});

Посмотрите этот для получения подробной информации или вы также можете проверить MDN для цикла через массив в JavaScript и с помощью проверки jQuery jQuery для каждого.

  • 5
    Обидно, что ES5 forEach не находится на вершине ответов, потому что он наиболее близко соответствует тому, о чем просил ОП.
25

Я бы полностью рекомендовал использовать библиотеку underscore.js. Он предоставляет вам различные функции, которые можно использовать для перебора массивов/коллекций.

Например:

_.each([1, 2, 3], function(num){ alert(num); });
=> alerts each number in turn...
  • 7
    Для новых исследователей этого вопроса я просто хотел бы указать на Lo-Dash , духовного преемника Underscore, который во многом улучшил его.
  • 3
    Зачем использовать underscore если в ECMA-262 добавлен метор forEach . Родной код всегда лучше.
25

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

var i = 0,
     item;

// note this is weak to sparse arrays or falsey values
for ( ; item = myStringArray[i++] ; ){ 
    item; // This is the string at the index.
}

Или если вы действительно хотите получить идентификатор и иметь классический цикл for:

var i = 0,
    len = myStringArray.length; // cache the length

for ( ; i < len ; i++ ){
    myStringArray[i]; // Don't use this if you plan on changing the length of the array
}

Современные браузеры поддерживают методы итератора forEach, map, reduce, filter и множество других методов в Array prototype.

  • 3
    Обратите внимание, что некоторые интерпретаторы (например, V8) автоматически кэшируют длину массива, если код вызывается достаточное количество раз, и обнаруживает, что длина не изменяется циклом.
  • 0
    Спасибо за информацию @Phrogz, это правда, что виртуальная машина может оптимизировать много вещей, но, поскольку в старых браузерах этого нет, лучше бы оптимизировать ее, так как она очень дешевая.
Показать ещё 4 комментария
23

Контур массива:

for(var i = 0; i < things.length; i++){
    var thing = things[i];
    console.log(thing);
}

Цикл объекта:

for(var prop in obj){
    var propValue = obj[prop];
    console.log(propValue);
}
22

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

var arr = [1, 2, 3, 4, 5];

Это решения:

1) для цикла

Для цикла - это общий способ циклирования массивов в JavaScript, но не считается самым быстрым решением для больших массивов:

for (var i=0, l=arr.length; i<l; i++) { 
  console.log(arr[i]);
}

2) Пока цикл

В то время как цикл рассматривается как самый быстрый способ прокрутки длинных массивов, но обычно менее используемый в JavaScript:

let i=0;

while (arr.length>i) {
    console.log(arr[i]);
    i++;
}

3) Во время
Делайте, делая то же самое, что и с некоторыми различиями синтаксиса, как показано ниже:

let i=0;
do {
  console.log(arr[i]);
  i++;
}
while (arr.length>i);

Это основные способы создания javascript-циклов, но есть еще несколько способов сделать это.

Также мы используем for in цикла for in для циклизации объектов в javascript.

Также посмотрите на функции map(), filter(), reduce() т.д. На Array в JavaScript. Они могут делать вещи гораздо быстрее и лучше, чем использовать while и for.

Это хорошая статья, если вам нравится больше узнать об асинхронных функциях над массивами в JavaScript.

Функциональное программирование в наши дни сильно отразилось на мировом развитии. И по уважительной причине: функциональные методы могут помочь вам написать более декларативный код, который легче понять с первого взгляда, рефакторингом и тестом.

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

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

Это также означает, что вам больше не придется писать цикл for.

Подробнее >> здесь:

  • 0
    Есть ли разница в производительности перед циклом for и циклом while при итерации по массиву? У меня сложилось впечатление, что различия были в основном синтаксическими
19

Если кого-то интересует производительность нескольких механизмов, доступных для итераций Array, я подготовил следующие тесты JSPerf:

https://jsperf.com/fastest-array-iterator

Изображение 2021

Результаты:

Традиционный итератор for(), безусловно, является самым быстрым методом, особенно при использовании с кэшированной длиной массива.

let arr = [1,2,3,4,5];

for(let i=0, size=arr.length; i<size; i++){
    // do something
}

Array.prototype.forEach() и Array.prototype.map() являются наиболее медленными приближениями, вероятно, вследствие накладных расходов на вызов функции

  • 0
    лучше использовать i = i +1 вместо i++
19

Если вы используете библиотеку jQuery, рассмотрите возможность использования http://api.jquery.com/jQuery.each/

Из документации:

jQuery.each( collection, callback(indexInArray, valueOfElement) )

Возвраты: объект

Описание: Общая функция итератора, которая может использоваться для беспрепятственной итерации по объектам и массивам. Массивы и объекты типа массива с свойством length (например, объект аргументов функции) повторяются с помощью числового индекса от 0 до длины-1. Другие объекты повторяются через их именованные свойства.

Функция $.each() не совпадает с $(selector).each(), которая используется для итерации исключительно над объектом jQuery. Функция $.each() может использоваться для итерации по любой коллекции, будь то карта (объект JavaScript) или массив. В случае массива обратный вызов каждый раз передается индексом массива и соответствующим значением массива. (Доступ к this значению также можно получить через this ключевое слово, но Javascript всегда будет переносить this значение как Object даже если это простая строка или числовое значение.) Метод возвращает свой первый аргумент - объект, который был итерирован.

  • 7
    JQuery для всего?
  • 6
    Согласился с исключением. Не стоит недооценивать влияние дополнительных зависимостей. Я бы посоветовал против этого, за исключением кода, который в любом случае уже активно использует jQuery.
Показать ещё 1 комментарий
16

Я еще не видел этот вариант, который мне лично нравится лучше всего:

Учитывая массив:

var someArray = ["some", "example", "array"];

Вы можете запрограммировать его без доступа к свойству length:

for (var i=0, item; item=someArray[i]; i++) {
  // item is "some", then "example", then "array"
  // i is the index of item in the array
  alert("someArray[" + i + "]: " + item);
}

См. этот JsFiddle, демонстрирующий, что: http://jsfiddle.net/prvzk/

Это работает только для массивов, которые не являются разреженными. Это означает, что на каждом индексе в массиве действительно есть значение. Тем не менее, я обнаружил, что на практике я почти никогда не использую разреженные массивы в Javascript... В таких случаях обычно проще использовать объект в качестве карты/хеш-таблицы. Если у вас есть разреженный массив и вы хотите зациклиться на 0.. length-1, вам понадобится построить for (var я = 0; я < someArray.length; ++ i), но вам все равно нужно, если внутри чтобы проверить, действительно ли элемент в текущем индексе определен.

Кроме того, как упоминает CMS в комментарии ниже, вы можете использовать это только на массивах, которые не содержат значений фальшивых значений. Массив строк из примера работает, но если у вас есть пустые строки или цифры 0 или NaN и т.д., Цикл будет прерваться преждевременно. Снова на практике это почти никогда не проблема для меня, но это то, что нужно помнить, что заставляет задуматься, прежде чем использовать его... Это может дисквалифицировать его для некоторых людей:)

Что мне нравится в этом цикле:

  • Короче писать
  • Нет необходимости в доступе (не говоря уже о кеше) свойства length
  • Элемент доступа автоматически определяется в цикле тело под названием, которое вы выбираете.
  • Совмещает очень естественно с array.push и array.splice для использования массивов, таких как списки/стеки.

Причина этого в том, что спецификация массива требует, чтобы при чтении элемента из индексa >= длина массива он вернет undefined. Когда вы пишете в такое место, оно фактически обновит длину.

Для меня эта конструкция наиболее точно эмулирует синтаксис Java 5, который мне нравится:

for (String item : someArray) {
}

... с дополнительным преимуществом, также зная о текущем индексе внутри цикла

  • 13
    Обратите внимание, что при таком подходе цикл остановится, как только он найдет значение Falsey , такое как пустая строка, 0 , false , NaN , null или undefined , даже до того, как i достигну длины, например: jsfiddle.net/prvzk/1
  • 3
    Условием цикла может быть (item=someArray[i]) !== undefined .
14

Есть несколько способов сделать это в JavaScript. Первые два примера - это образцы JavaScript. Третий использует библиотеку JavaScript, то есть jQuery, используя функцию .each().

var myStringArray = ["hello", "World"];
for(var i in myStringArray) {
  alert(myStringArray[i]);
}

var myStringArray = ["hello", "World"];
for (var i=0; i < myStringArray.length; i++) {
  alert(myStringArray[i]);
}

var myStringArray = ["hello", "World"];
$.each(myStringArray, function(index, value){
  alert(value);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  • 0
    for...in следует избегать для объектов, подобных массиву
14

Самый элегантный и быстрый способ

var arr = [1, 2, 3, 1023, 1024];
for (var value; value = arr.pop();) {
    value + 1
}

http://jsperf.com/native-loop-performance/8


Отредактировано (потому что я ошибался)


Сравнение методов для цикла через массив из 100000 элементов и выполнять минимальную операцию с новым значением каждый раз.

Приготовление:

<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script>
    Benchmark.prototype.setup = function() {
        // Fake function with minimal action on the value
        var tmp = 0;
        var process = function(value) {
            tmp = value; // Hold a reference to the variable (prevent engine optimisation?)
        };

        // Declare the test Array
        var arr = [];
        for (var i = 0; i < 100000; i++)
            arr[i] = i;
    };
</script>

Тесты:

<a href="http://jsperf.com/native-loop-performance/16" 
   title="http://jsperf.com/native-loop-performance/16"
><img src="http://i.imgur.com/YTrO68E.png" title="Hosted by imgur.com" /></a>
  • 0
    Этот цикл не соответствует порядку элементов в массиве.
  • 0
    Мой тест был неверным. Это правильно, показывая все петли сейчас. jsperf.com/native-loop-performance/16
Показать ещё 2 комментария
14

Существует метод для итерации только собственных свойств объекта, не включая прототипов:

for (var i in array) if (array.hasOwnProperty(i)) {
    // do something with array[i]
}

но он все равно будет перебирать настраиваемые свойства.

В javascript любое настраиваемое свойство может быть назначено любому объекту, включая массив.

Если требуется итерация по разреженному массиву, следует использовать for (var i = 0; i < array.length; i++) if (i in array) или array.forEach с помощью es5shim.

  • 0
    А как насчет использования for (var i in array) if (++i) ?
10

В JavaScript существует так много решений для цикла массива.

Нижеприведенный код

/** Declare inputs */
const items = ['Hello', 'World']

/** Solution 1. Simple for */
console.log('solution 1. simple for')

for (let i = 0; i < items.length; i++) {
  console.log(items[i])
}

console.log()
console.log()

/** Solution 2. Simple while */
console.log('solution 2. simple while')

let i = 0
while (i < items.length) {
  console.log(items[i++])
}

console.log()
console.log()

/** Solution 3. forEach*/
console.log('solution 3. forEach')

items.forEach(item => {
  console.log(item)
})

console.log()
console.log()

/** Solution 4. for-of*/
console.log('solution 4. for-of')

for (const item of items) {
  console.log(item)
}

console.log()
console.log()
10

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

var i, max, myStringArray = ["Hello","World"];
for (i = 0, max = myStringArray.length; i < max; i++) {
    alert(myStringArray[i]);
   //Do something
}

Если порядок итераций не имеет значения, вы должны попробовать обратный цикл, это быстрее, поскольку он уменьшает проверку служебных данных и декремент в одном утверждении:

var i,myStringArray = ["item1","item2"];
for (i =  myStringArray.length; i--) {
    alert(myStringArray[i]);
}

или лучше и чище использовать цикл while:

var myStringArray = ["item1","item2"],i = myStringArray.length;
while(i--) {
   // do something with fruits[i]
}
9

Лучший способ, по-моему, использовать функцию Array.forEach. Если вы не можете использовать это, я бы предложил получить polyfill из MDN, чтобы сделать я доступным, это, безусловно, самый безопасный способ перебора массива в JavaScript.

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

Так как другие предложили, это почти всегда то, что вы хотите:

var numbers = [1,11,22,33,44,55,66,77,88,99,111];
var sum = 0;
numbers.forEach(function(n){
  sum += n;
});

Это гарантирует, что все, что вам нужно в области обработки массива, остается в пределах этой области и что вы обрабатываете только значения массива, а не свойства объекта и других членов, что и есть для.. в.

Использование обычного стиля c для цикла работает в большинстве случаев, важно помнить, что все в цикле разделяет его область действия с остальной частью вашей программы, {} не создает новую область.

Следовательно:

var sum = 0;
var numbers = [1,11,22,33,44,55,66,77,88,99,111];

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

alert(i);

выводит "11" - это может быть или не быть тем, что вы хотите.

Рабочий пример jsFiddle: https://jsfiddle.net/workingClassHacker/pxpv2dh5/7/

9

Короткий ответ: да. Вы можете сделать это:

var myArray = ["element1", "element2", "element3", "element4"];

for (i = 0; i < myArray.length; i++) {
  console.log(myArray[i]);
}

В консоли браузера вы можете увидеть что-то вроде "element1", "element2" и т.д., напечатанных.

8

Если вы хотите использовать jQuery, он имеет хороший пример в своей документации:

 $.each([ 52, 97 ], function( index, value ) {
      alert( index + ": " + value );
 });
8

Например, я использовал в консоли Firefox:

[].forEach.call(document.getElementsByTagName('pre'), function(e){ 
   console.log(e);
})
8
var x = [4, 5, 6];
for (i = 0, j = x[i]; i < x.length; j = x[++i]) {
    console.log(i,j);
}

Много чище...

  • 0
    Вы имели в виду «х =» в первой строке?
7

Простое однострочное решение

arr = ["table", "chair"];

// solution
arr.map((e) => {
  console.log(e);
  return e;
});
  • 3
    Вы бы предпочли использовать .forEach() и отбросить return e;
  • 3
    как следует из map , функция map предназначена для отображения определенного значения в другое, поэтому я бы не советовал использовать это значение для этого конкретного примера.
7

Это не на 100% идентично, но похоже:

   var myStringArray = ['Hello', 'World']; // array uses [] not {}
    for (var i in myStringArray) {
        console.log(i + ' -> ' + myStringArray[i]); // i is the index/key, not the item
    }
  • 1
    Кажется, что это столкнулось бы с подобными проблемами, как и в случае использования с объектом массива, в этом случае переменные-члены прототипа также были бы перехвачены в for.
6

Уверен, что он неэффективен и многие его презирают, но он один из ближайших к упомянутому:

var myStringArray = ["Hello","World"];
myStringArray.forEach(function(f){
    // Do something
})
  • 2
    Эта точная функциональность уже является частью ответа Марка Рида.
5

Кажется, что перечислены все варианты, кроме forEach по lodash:

_.forEach([1, 2], (value) => {
  console.log(value);
});
5
var myStringArray = ["hello", "World"];
myStringArray.forEach(function(val, index){
   console.log(val, index);
})
5

Ну, как насчет этого:

for (var key in myStringArray) {
    console.log(myStringArray[key]);
}
  • 9
    Циклы for / in не рекомендуются для перечисления массива, так как порядок перечисления не гарантируется, и он перечисляет свойства, а не только элементы массива. Для получения дополнительной информации см. Stackoverflow.com/questions/500504/… или даже принятый ответ на этот вопрос; stackoverflow.com/a/3010848/444991
  • 0
    хорошо, спасибо за обновление .. а как насчет ситуации, когда мы не заботимся о порядке массива? Будет ли это по-прежнему препятствовать?
Показать ещё 1 комментарий
4

Резюме:

При переборе массива мы часто хотим достичь одной из следующих целей:

  1. Создайте новый массив, оставьте исходный нетронутым: используйте map()
  2. Выполните действие с/над каждым элементом массива и, возможно, for..of массив: используйте for..of, forEach() или обычный цикл for

Примеры:

const arr1 = [1, 2, 3];

const arr2 = arr1.map(el => el * 2);

// with map we create a new arr2, arr1 is left untouched
console.log(arr2, arr1);


// regular for loop
for (let i = 0; i < arr1.length; i++) {
  console.log(arr1[i]);
}

console.log('\n');

// for of loop
for (let el of arr1) {
  console.log(el);

}

console.log('\n');


// forEach()
arr1.forEach(el => {
  console.log(el)
})

Какой использовать?

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

  1. Если вы хотите манипулировать массивом, но оставить старый массив нетронутым (например, функциональное программирование), вы можете лучше всего использовать map() для итерации. Когда вам не нужно возвращать новый массив, не используйте map(). map() имеет самую низкую производительность среди всех циклических методов.
  2. Когда производительность играет роль, когда вам нужно перебрать очень много, обычный цикл for:

for(let i=0; я < arr.length; i++) {}

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

4

Лучше использовать последовательный цикл for:

for (var i = 0; i < myStringArray.length; i++) {
    // Do something
}
3
var obj = ["one","two","three"];

for(x in obj){
    console.log(obj[x]);
}
1

Зацикливание массива рекурсивно

const data = ['one', 'two', 'three']

const loop = (items, index=0) => {
  if (items.length === index) {
    return;
  }
  console.log(items[index], index)
  loop(items, index+=1)
}

loop(data)
  • 0
    это, вероятно, не очень хороший способ, потому что он может генерировать очень глубокие стеки вызовов, поэтому эта функция может вызывать стекопотоки
0

var array = ['hai', 'hello', 'how', 'are', 'you']
$(document).ready(function () {
  $('#clickButton').click(function () {
    for (var i = 0; i < array.length; i++) {
      alert(array[i])
    }
  })
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<input id="clickButton" value="click Me" type="button"/>
<div id="show"></div>
  • 0
    Действительно ли было необходимо привнести в это jQuery или HTML?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню