Просмотр массива в JavaScript.

javascript arrays loops for-loop


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

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

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




Answer 1 CMS


У вас есть несколько вариантов:

1. Последовательность for цикла:

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

Pros

  • Работает на любой среде
  • Вы можете использовать break и continue операторы управления потоком

Cons

  • Слишком многословный
  • Imperative
  • Легко иметь отдельные ошибки (иногда их также называют ошибкой поста забора )

2.Массив.прототип.forEach

Спецификация ES5 представила множество полезных методов массива, один из них, Array.prototype.forEach , и это дает нам краткий способ перебора массива:

const array = ["one", "two", "three"]
array.forEach(function (item, index) {
  console.log(item, index);
});

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

А с синтаксисом функции стрелок ES6 он еще более лаконичен:

array.forEach(item => console.log(item));

Функции стрелок также широко применяются,если только вы не планируете поддерживать старинные платформы (например,IE11);вы также можете быть в безопасности.

Pros

  • Очень коротко и лаконично.
  • Declarative

Cons

  • Не могу использовать break / continue

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

array.filter(item => item.condition < 10)
     .forEach(item => console.log(item))

Имейте в виду, что если вы итерируете массив для создания другого массива из него , вам следует использовать map , я видел этот анти-паттерн очень много раз.

Anti-pattern:

const numbers = [1,2,3,4,5], doubled = [];

numbers.forEach((n, i) => { doubled[i] = n * 2 });

Правильный вариант использования карты :

const numbers = [1,2,3,4,5];
const doubled = numbers.map(n => n * 2);

console.log(doubled);

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

Anti-pattern:

const numbers = [1,2,3,4,5];
const sum = 0;
numbers.forEach(num => { sum += num });

Правильное использование уменьшить :

const numbers = [1,2,3,4,5];
const sum = numbers.reduce((total, n) => total + n, 0);

console.log(sum);

3. ES6 for-of утверждения

Стандарт ES6 вводит концепцию итерируемых объектов и определяет новую конструкцию для обхода данных, форму for...of оператора.

Этот оператор работает для любого типа итерируемого объекта, а также для генераторов (любой объект, имеющий свойство [Symbol.iterator] ).

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

let colors = ['red', 'green', 'blue'];
for (const color of colors){
    console.log(color);
}

Pros

  • Он может проводить итерации по большому количеству объектов.
  • Можно использовать обычные операторы управления потоком ( break / continue ).
  • Полезно для итераций последовательных асинхронных значений.

Cons

  • Если вы ориентируетесь на более старые браузеры, транспонированный вывод может вас удивить .

Не использовать for...in

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

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

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

Второй момент заключается в том, что это может создать много проблем, например, если вы Array.prototype объект 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 позволяет перечислять только собственные свойства , то есть только свойства, которыми физически обладает объект, без унаследованных свойств.

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




Answer 2 Mark Reed


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

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

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

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

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

(Переменная s отличается на каждой итерации, но все еще может быть объявлена ​​как const внутри тела цикла, если она там не изменена.)

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

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

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

Пока ваша реализация JavaScript совместима с предыдущей редакцией спецификации ECMAScript (которая, например, исключает версии Internet Explorer до 9), вы можете использовать метод итератора Array#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 выражения в условие цикла) может существенно на производительность, поскольку оно пропускает поиск свойств каждый раз; при использовании Rhino на моей машине ускорение составляет 43%.

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

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

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

myStringArray.forEach( function(s, i) {
   // ... do something with s and i ...
});

for ... of не дает индекс, связанный с каждым объектом, но пока объект, над которым вы перебираете, на самом деле является Array ( for .. of works для других итерируемых типов, которые могут не иметь этого метода), Вы можете использовать Array # записи чтобы изменить его на массив пар [index, item], а затем выполнить итерацию по нему:

for (const [i, s] of myStringArray.entries()) {
  // ... do something with s and i ...
}

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




Answer 3 hasen


Вы можете использовать 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;});

И теперь х равен [10,20,30,40] .

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

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 .




Answer 4 sebarmeli


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

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

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




Answer 5 Marlon Bernardes


...

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

Большинство других ответов верны, но они не упоминают (на момент написания этой статьи), что в 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/#For..of циклов

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

}