Всі способи перебору масиву в JavaScript

Зміст:

  • I. Перебір цих масивів
    1. Метод forEach і споріднені методи
    2. Цикл for

    3. Правильне використання циклу for...in
    4. Цикл for...of (неявне використання ітератора)
    5. Явне використання ітератора
  • II. Перебір массивоподобных об'єктів
    1. Використання способів перебору цих масивів
    2. Перетворення в справжній масив

    3. Зауваження по об'єктах середовища виконання


I. Перебір цих масивів
На даний момент є три способи перебору елементів цього масиву:
  1. метод
    Array.prototype.forEach
    ;
  2. класичний цикл
    for
    ;
  3. «правильно» побудований цикл
    for...in
    .
Крім того, незабаром, з появою нового стандарту ECMAScript 6 (ES 6), очікується ще два способи:
  1. цикл
    for of...
    (неявне використання ітератора);
  2. явне використання ітератора.

1. Метод forEach і споріднені методи

Якщо ваш проект розрахований на підтримку можливостей стандарту ECMAScript 5 (ES5), ви можете використовувати одну з його нововведень — метод forEach.

Приклад використання:
var a = ["a", "b", "с"];
a.forEach(function(entry) {
console.log(entry);
});

У загальному випадку використання
forEach
вимагає підключення бібліотеки емуляції es5-shim для браузерів, які не мають нативної підтримки цього методу. До них відносяться IE 8 і більш ранні версії, які досі подекуди ще використовуються.

До достоїнств
forEach
відноситься те, що тут не потрібно оголошувати локальні змінні для зберігання індексу та значення поточного елемента масиву, оскільки вони автоматично передаються у функцію зворотного виклику (колбек) в якості аргументів.

Якщо вас турбують можливі витрати на виклик колбека для кожного елемента, не хвилюйтеся і прочитайте це.

forEach
призначений для перебору всіх елементів масиву, але крім нього ES5 пропонує ще декілька корисних методів для перебору всіх або деяких елементів плюс виконання при цьому яких-небудь дій з ними:
  • every
    повертає
    true
    , якщо для кожного елемента масиву колбек повертає значення приводиться до
    true
    .
  • some
    повертає
    true
    , якщо хоча б для одного елемента масиву колбек повертає значення приводиться до
    true
    .
  • filter
    — створює новий масив, що включає ті елементи вихідного масиву, для яких колбек повертає
    true
    .
  • map
    — створює новий масив, що складається із значень возращаемых колбеком.
  • reduce
    — зводить масив до єдиного значення, застосовуючи колбек по черзі до кожного елементу масиву, починаючи з першого (може бути корисний для обчислення суми елементів масиву та інших підсумкових функцій).
  • reduceRight
    — працює аналогічно reduce, але перебирає елементи в зворотному порядку.

2. Цикл for

Старий добрий
for
рулить
:

var a = ["a", "b", "с"];
var index;
for (index = 0; index < a.length; index++) {
console.log(a[index]);
}

Якщо довжина масиву незмінна протягом всього циклу, а сам цикл належить критичному в плані продуктивності ділянки коду (що малоймовірно), то можна використовувати «більш оптимальну» версію
for
з зберіганням довжини масиву:

var a = ["a", "b", "с"];
var index, len;
for (index = 0, len = a.length; index < len; index++) {
console.log(a[index]);
}

Теоретично цей код повинен виконуватися трохи швидше, ніж попередній.

Якщо порядок перебору елементів не важливий, то можна піти ще далі в плані оптимізації і позбутися від змінної для зберігання довжини масиву, змінивши порядок перебору на зворотний:

var a = ["a", "b", "с"];
var index;
for (index = a.length - 1; index >= 0; --index) {
console.log(a[index]);
}

Тим не менш, в сучасних движках JavaScript подібні ігри з оптимізацією зазвичай нічого не значать.

3. Правильне використання циклу for...in

Якщо вам порадять використовувати цикл
for...in
, пам'ятайте, що перебір масивів — не те, для чого він призначений. Всупереч поширеній помилці цикл
for...in
не перебирає індекси масиву, а перечислимого властивості об'єкта.

Тим не менш, в деяких випадках, таких як перебір розріджених масивів,
for...in
може виявитися корисним, якщо тільки дотримуватися при цьому запобіжні заходи, як показано в прикладі нижче:

// a - масив розріджений
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "с";
for (var key in a) {
if (a.hasOwnProperty(key) &&
/^0$|^[1-9]\d*$/.test(key) &&
key <= 4294967294) {
console.log(a[key]);
}
}

У даному прикладі на кожній ітерації циклу виконується дві перевірки:
  1. те, що масив має властивість з ім'ям
    key
    (не наследованное з його прототипу).
  2. те, що
    key
    — рядок, що містить десятковий запис цілого числа, значення якого менше
    4294967294
    . Звідки береться останнє число? визначення індексу масиву в ES5, з якого випливає, що найбільший індекс, який може мати елемент в масиві:
    (2^32 - 2) = 4294967294
    .
Звичайно, такі перевірки віднімуть зайвий час при виконанні циклу. Але у випадку розрідженого масиву цей спосіб більш ефективний, ніж цикл
for
, оскільки в цьому випадку перебираються тільки ті елементи, які явно визначені в масиві. Так, в прикладі вище буде виконано всього 3 ітерації (для індексів 0, 10 і 10000) — проти 10001 в цикл
for
.

Щоб не писати такий громіздкий код перевірок кожен раз, коли потрібно перебір масиву, можна оформити його у вигляді окремої функції:

function arrayHasOwnIndex(array, key) {
return array.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294;
}

Тоді тіло циклу з прикладу значно скоротиться:

for (key in a) {
if (arrayHasOwnIndex(a, key)) {
console.log(a[key]);
}
}

Розглянутий вище код перевірок є універсальним, придатним для всіх випадків. Але замість нього можна використовувати більш коротку версію, хоча формально і не зовсім правильну, але, тим не менш, підходить для більшості випадків:

for (key in a) {
if (a.hasOwnProperty(key) && String(parseInt(key, 10)) === key) {
console.log(a[key]);
}
}

4. Цикл for...of (неявне використання ітератора)

ES6, поки все ще перебуває в статусі чернетки, повинен ввести в JavaScript ітератори.

Ітератор — це реалізований об'єктом протокол, який визначає стандартний спосіб отримання послідовності значень (кінцевої або нескінченної).
Об'єкт має ітератор, якщо в ньому визначено метод
next()
— функція без аргументів, що повертає об'єкт з двома властивостями:
  1. done
    (
    boolean
    ) — повертає значення
    true
    , якщо ітератор досяг кінця итерируемой послідовності. В іншому випадку має значення
    false
    .
  2. value
    — визначає значення, що повертається ітератором. Може бути не визначено (відсутнім), якщо властивість
    done
    має значення
    true
    .
Вбудовані об'єкти, в т.ч. справжні масиви, мають ітератори за замовчуванням. Найпростіший спосіб застосування ітератора у цих масивах — використовувати нову конструкцію
for of...
.

Приклад використання
for of...
:

var val;
var a = ["a", "b", "с"];
for (val of a) {
console.log(val);
}

У наведеному прикладі цикл
for of...
неявно викликає ітератор об'єкта Array для отримання кожного значення масиву.

5. Явне використання ітератора

Ітератори можна також використовувати і явно, правда, в цьому випадку код стає значно складніше, порівняно з циклом
for of...
. Виглядає це приблизно так:

var a = ["a", "b", "с"];
var entry;
while (!(entry = a.next()).done) {
console.log(entry.value);
}


II. Перебір массивоподобных об'єктів
Крім цих масивів, JavaScript зустрічаються також массивоподобные об'єкти. З цими масивами їх ріднить те, що вони мають властивість
length
та властивості з іменами у вигляді чисел, що відповідають елементам масиву. В якості прикладів можна назвати DOM колекції
NodeList
і псевдомассив
arguments
, доступний всередині будь-якої функції/методу.

1. Використання способів перебору цих масивів

Як мінімум більшість, якщо не всі, способи перебору цих масивів можуть бути застосовані для перебору массивоподобных об'єктів.

Конструкції
for
та
for...in
можуть бути застосовані до массивоподобным об'єктів точно тим же шляхом, що і до цих масивів.

forEach
та інші методи
Array.prototype
також застосовні до массивоподобным об'єктів. Для цього потрібно використовувати виклик Function.call або Function.apply.

Наприклад, якщо ви хочете застосувати
forEach
властивості
childNodes
об'єкта
Node
, то це робиться так:

Array.prototype.forEach.call(node.childNodes, function(child) {
// робимо що-небудь з об'єктом child
});

Для зручності подальшого використання цього прийому, можна оголосити посилання на метод
Array.prototype.forEach
в окремій змінній і використовувати її як скорочення:

// (Передбачається, що весь код нижче знаходиться в одній області видимості)
var forEach = Array.prototype.forEach;

// ...

forEach.call(node.childNodes, function(child) {
// робимо що-небудь з об'єктом child
});

Якщо в массивоподобном об'єкті є ітератор, то його можна використовувати явно або неявно для перебору об'єкта таким же способом, як і для справжніх масивів.

2. Перетворення в справжній масив

Є також ще один дуже простий, спосіб перебору массивоподобного об'єкта: перетворити його на справжній масив і використовувати будь-який з розглянутих вище способів перебору цих масивів. Для перетворення можна використовувати універсальний метод
Array.prototype.slice
, який може бути застосований до будь массивоподобному об'єкту. Робиться це дуже просто, як показано в прикладі нижче:

var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);

Наприклад, якщо ви хочете перетворити колекцію
NodeList
в даний масив, вам потрібен приблизно такий код:

var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);

3. Зауваження по об'єктах середовища виконання

Якщо ви застосовуєте методи
Array.prototype
до об'єктів середовища виконання (таких як DOM колекції), то ви повинні мати на увазі, що правильна робота цих методів не гарантована у всіх середовищах виконання (у т. ч. в браузерах). Це залежить від поведінки конкретного об'єкта в конкретному середовищі виконання, якщо точніше, від того, як в цьому об'єкті реалізована абстрактна операція
HasProperty
. Проблема в тому, що сам стандарт ES5 допускає можливість неправильного поведінки об'єкта по відношенню до цієї операції (див. §8.6.2).

Тому важливо тестувати роботу методів
Array.prototype
в кожній середовищі виконання (браузері), в якій планується використання вашого додатка.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.