map, filter, reduce в JavaScript
map, filter, reduce — три кита функционального перебора массивов в JavaScript: трансформация, фильтрация и свёртка.
map, filter и reduce — методы, которые обходят массив и возвращают новый результат, не изменяя исходный. Они принимают функцию-колбэк и применяют её к каждому элементу.
map — трансформация
Метод map создаёт новый массив, применяя функцию к каждому элементу исходного. Исходный массив остаётся нетронутым.
const prices = [100, 200, 300];
// умножаем каждый элемент на 1.2
const withTax = prices.map(price => price * 1.2);
console.log(withTax); // [120, 240, 360]
console.log(prices); // [100, 200, 300] — не изменился
Вывод:
[120, 240, 360] [100, 200, 300]
Колбэк получает три аргумента: текущий элемент, его индекс и весь массив. Обычно используют только первый:
const names = ['аня', 'боря', 'вика'];
const upper = names.map((name, index) => `${index + 1}. ${name.toUpperCase()}`);
console.log(upper);
// ['1. АНЯ', '2. БОРЯ', '3. ВИКА']
Вывод:
['1. АНЯ', '2. БОРЯ', '3. ВИКА']
filter — фильтрация
Метод filter возвращает новый массив, содержащий только те элементы, для которых колбэк вернул true.
const scores = [45, 82, 67, 30, 91, 58];
const passed = scores.filter(score => score >= 60);
console.log(passed); // [82, 67, 91]
// можно комбинировать несколько условий
const highPass = scores.filter(score => score >= 60 && score <= 90);
console.log(highPass); // [82, 67]
Вывод:
[82, 67, 91] [82, 67]
reduce — свёртка
reduce «сворачивает» массив в одно значение, накапливая результат через аккумулятор. Второй аргумент метода — начальное значение аккумулятора.
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 15
// произведение
const product = numbers.reduce((acc, num) => acc * num, 1);
console.log(product); // 120
Вывод:
15 120
Всегда указывайте начальное значение аккумулятора (
0,[],{}). Без него на пустом массивеreduceбросит исключение, а на массиве из одного элемента просто вернёт его без вызова колбэка.
Цепочки методов
Методы можно выстраивать в цепочку: каждый возвращает новый массив, и к нему сразу применяется следующий метод.
const orders = [
{ product: 'книга', amount: 500 },
{ product: 'ручка', amount: 50 },
{ product: 'ноутбук', amount: 45000 },
{ product: 'тетрадь', amount: 80 },
];
// дорогие товары (> 100 руб) — сумма их стоимостей
const total = orders
.filter(o => o.amount > 100)
.map(o => o.amount)
.reduce((acc, a) => acc + a, 0);
console.log(total); // 45500
Вывод:
45500
Частые ошибки
- Забыть return в многострочном колбэке. Стрелочная функция без фигурных скобок возвращает результат неявно, а с фигурными — нужен явный
return. - Изменять исходный массив внутри map/filter. Они предназначены для создания нового массива, а не для мутации исходного.
- Не указывать начальное значение для reduce. На пустом массиве без начального значения — ошибка.
// частая ошибка: нет return
const doubled = [1, 2, 3].map(n => {
n * 2; // забыли return — возвращает undefined
});
console.log(doubled); // [undefined, undefined, undefined]
// правильно
const doubled2 = [1, 2, 3].map(n => n * 2);
console.log(doubled2); // [2, 4, 6]
Вывод:
[undefined, undefined, undefined] [2, 4, 6]
Коротко
map(fn)— трансформирует каждый элемент, возвращает новый массив той же длины.filter(fn)— оставляет только элементы, для которых колбэк вернулtrue.reduce(fn, init)— сворачивает массив в одно значение через аккумулятор.- Методы не мутируют исходный массив и хорошо объединяются в цепочки.