map, filter и reduce
Большинство задач с массивами сводятся к трём действиям: изменить каждый элемент, отобрать подходящие или посчитать итог. Для них есть методы map(), filter() и reduce(). Код с ними короче цикла, и по имени метода сразу видно, что он делает.
map — преобразовать каждый элемент
map() вызывает функцию для каждого элемента и собирает её результаты в новый массив той же длины:
const numbers = [1, 2, 3];
const doubled = numbers.map((n) => n * 2);
console.log(doubled.join(', ')); // 2, 4, 6Исходный массив numbers не меняется — map() всегда возвращает новый.
filter — отобрать подходящие
filter() оставляет только те элементы, для которых функция вернула true. Такую функцию-проверку называют условием или предикатом:
const numbers = [5, 12, 8, 20];
const big = numbers.filter((n) => n > 10);
console.log(big.join(', ')); // 12, 20Если ни один элемент не подошёл, получится пустой массив.
reduce — свести к одному значению
reduce() проходит по массиву и накапливает результат. Функция получает накопленное значение (его часто называют sum или acc) и очередной элемент, а второй аргумент reduce() — начальное значение:
const prices = [100, 250, 400];
const total = prices.reduce((sum, price) => sum + price, 0);
console.log(total); // 750На первом шаге sum равно 0, на втором — 100, на третьем — 350, и в конце получается 750.
Массив объектов
Чаще всего эти методы работают с массивами объектов. Объект — это значение в фигурных скобках, которое хранит данные под именами: product.title читает свойство title. Подробно объекты разобраны в следующей главе.
const products = [
{ title: 'Чай', price: 5 },
{ title: 'Кофе', price: 12 },
];
const titles = products.map((product) => product.title);
console.log(titles.join(', ')); // Чай, КофеЦепочка методов
map() и filter() возвращают массив, поэтому следующий метод можно вызвать сразу после предыдущего:
const orders = [
{ total: 500, paid: true },
{ total: 300, paid: false },
{ total: 200, paid: true },
];
const paidSum = orders
.filter((order) => order.paid)
.map((order) => order.total)
.reduce((sum, total) => sum + total, 0);
console.log(paidSum); // 700Цепочку читают сверху вниз: оплаченные заказы, их суммы, общий итог.
Частая ошибка
Если тело стрелочной функции взято в фигурные скобки, значение нужно вернуть через return. Без него функция возвращает undefined:
const numbers = [1, 2, 3];
const wrong = numbers.map((n) => { n * 2; });
const right = numbers.map((n) => { return n * 2; });
console.log(wrong[0]); // undefined
console.log(right.join(', ')); // 2, 4, 6В короткой записи без скобок, (n) => n * 2, return подразумевается сам.