Урок 02

Массивы: перебор

for

Классический:

const items = ['a', 'b', 'c'];

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

Можно break и continue.

for...of

Современный:

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

С индексом:

for (const [index, item] of items.entries()) {
    console.log(index, item);
}

Можно break, continue, await.

for...in

Не используй для массивов. Итерирует по ключам, включая неиндексные свойства:

const arr = [1, 2, 3];
arr.custom = 'x';

for (const key in arr) {
    console.log(key); // '0', '1', '2', 'custom'
}

forEach

items.forEach((item, index, array) => {
    console.log(item, index);
});

Нельзя прервать. Возвращает undefined.

map

Преобразует каждый элемент, возвращает новый массив:

const doubled = [1, 2, 3].map((x) => x * 2); // [2, 4, 6]

С индексом:

['a', 'b'].map((item, i) => `${i}: ${item}`); // ['0: a', '1: b']

filter

Оставляет подходящие:

const evens = [1, 2, 3, 4].filter((x) => x % 2 === 0); // [2, 4]

reduce

Сворачивает в одно значение:

const sum = [1, 2, 3].reduce((acc, x) => acc + x, 0); // 6

С объектом:

const grouped = ['a', 'b', 'a'].reduce((acc, x) => {
    acc[x] = (acc[x] ?? 0) + 1;
    return acc;
}, {});
// { a: 2, b: 1 }

Без начального значения — первое значение берётся как стартовое:

[1, 2, 3].reduce((acc, x) => acc + x); // 6

Без начального значения на пустом массиве — ошибка:

[].reduce((a, b) => a + b); // TypeError

Всегда указывай начальное значение.

some и every

[1, 2, 3].some((x) => x > 2);   // true
[1, 2, 3].every((x) => x > 0);  // true

some — хотя бы один. every — все.

find и findIndex

[1, 2, 3].find((x) => x > 1);       // 2
[1, 2, 3].findIndex((x) => x > 1);  // 1
[1, 2, 3].findLast((x) => x > 1);   // 3

Цепочки

const result = users
    .filter((u) => u.active)
    .map((u) => u.name)
    .sort();

Каждый метод возвращает новый массив. Оригинал не меняется.

Прерывание цепочек

forEach, map, filter нельзя прервать. Для прерывания — for...of или some/every:

[1, 2, 3, 4].some((x) => {
    if (x > 2) return true; // прервёт
    console.log(x);
    return false;
});

Итераторы

const iterator = arr[Symbol.iterator]();
iterator.next(); // { value: 1, done: false }

Используется редко напрямую.

entries, keys, values

const arr = ['a', 'b'];

[...arr.entries()]; // [[0, 'a'], [1, 'b']]
[...arr.keys()];    // [0, 1]
[...arr.values()];  // ['a', 'b']

Производительность

  • for и for...of быстрее forEach
  • map, filter создают новые массивы
  • Цепочки map + filter проходят массив несколько раз
  • reduce — один проход

Для больших данных — for или reduce.

Итоги

  • for, for...of, forEach — перебор
  • map, filter, reduce — преобразование
  • some, every, find — проверки
  • forEach не прерывается
  • Цепочки создают новые массивы
  • for...of — универсальный