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) — сворачивает массив в одно значение через аккумулятор.
  • Методы не мутируют исходный массив и хорошо объединяются в цепочки.
Проверьте себя
1. Что вернёт [1, 2, 3].map(n => n * 2)?
A[1, 2, 3]
B[2, 4, 6]
C6
Dundefined
2. Метод filter вернёт элементы, для которых колбэк вернул...
Aлюбое значение
Btrue
Cfalse
D0
3. Каково значение result после: const result = [1,2,3].reduce((acc, n) => acc + n, 10)?
A6
B16
C10
D1
4. Что произойдёт, если в map написать колбэк с фигурными скобками, но без return?
AВернётся исходный массив
BКаждый элемент будет undefined в результате
CОшибка компиляции
Dmap вернёт пустой массив
Поддержать проект