EvolCode
треки/С нуля·08 / 11
7 мин чтения

map, filter, reduce — функции высших порядков

ИИ почти никогда не пишет `for (let i = 0; i < arr.length; i++)`. Вместо этого — `arr.map(...)`, `arr.filter(...)`, `arr.reduce(...)`. Это короче, надёжнее, и сразу видно что код делает. Разберём все три и научимся читать.

map — преобразовать каждый элемент

arr.map(fn) — пробегает по массиву, для каждого элемента вызывает функцию, собирает результаты в НОВЫЙ массив той же длины. Не трогает оригинал. Используют когда нужно «преобразовать каждый» — например взять имена пользователей: users.map(u => u.name). Или удвоить числа: nums.map(n => n * 2).

filter — оставить только подходящие

arr.filter(fn) — для каждого элемента вызывает функцию, возвращает НОВЫЙ массив только из тех, где функция вернула true. Используют для «отфильтровать»:

$ users.filter(u => u.age >= 18)

(только взрослые). tasks.filter(t => !t.done) (только незавершённые). Если ничего не подошло — пустой массив.

reduce — свернуть массив в одно значение

arr.reduce(fn, начальное) — пробегает по массиву, аккумулируя результат. На каждом шаге функция получает аккумулятор и текущий элемент, возвращает новый аккумулятор. Используется для сумм, счётчиков, преобразований в объект. Самый сложный из трёх — но самый мощный.

Цепочки — сила всех вместе

Эти функции возвращают массив, поэтому их можно цеплять. Хочешь сумму цен взрослых пользователей?

$ users.filter(u => u.age >= 18).map(u => u.price).reduce((sum, p) => sum + p, 0)

Каждый шаг читается отдельно: «фильтр взрослые → взять цены → сложить». Сравни с одним для-циклом — намного чище.

примерjavascript
const товары = [
  { имя: 'Молоко', цена: 95, доступен: true },
  { имя: 'Хлеб',   цена: 45, доступен: false },
  { имя: 'Сыр',    цена: 280, доступен: true },
  { имя: 'Йогурт', цена: 65, доступен: true },
];

// === MAP — преобразуем каждый ===
const имена = товары.map(t => t.имя);
// ['Молоко', 'Хлеб', 'Сыр', 'Йогурт']

const сКидкой = товары.map(t => ({
  ...t,
  цена: t.цена * 0.9,                  // -10%
}));
// новый массив объектов с уменьшенной ценой

// === FILTER — отбираем по условию ===
const доступные = товары.filter(t => t.доступен);
// [Молоко, Сыр, Йогурт]

const дешёвые = товары.filter(t => t.цена < 100);
// [Молоко, Хлеб, Йогурт]

// === REDUCE — сворачиваем в одно значение ===
const сумма = товары.reduce((acc, t) => acc + t.цена, 0);
// 485 — сумма всех цен

// Сгруппировать в объект:
const поДоступности = товары.reduce((acc, t) => {
  const ключ = t.доступен ? 'есть' : 'нет';
  acc[ключ] = acc[ключ] || [];
  acc[ключ].push(t);
  return acc;
}, {});
// { есть: [Молоко, Сыр, Йогурт], нет: [Хлеб] }

// === ЦЕПОЧКА — сила вместе ===
const суммаДешёвыхДоступных = товары
  .filter(t => t.доступен)              // есть в наличии
  .filter(t => t.цена < 100)            // дешёвые
  .reduce((sum, t) => sum + t.цена, 0); // сумма
// 160 (Молоко 95 + Йогурт 65)

// === Сравни с обычным циклом ===
let сумма_обычно = 0;
for (let i = 0; i < товары.length; i++) {
  if (товары[i].доступен && товары[i].цена < 100) {
    сумма_обычно += товары[i].цена;
  }
}
// Тот же результат, но 4 строки против 3
// и читать сложнее — нужно строить картинку в голове

map / filter / reduce — три инструмента которые покрывают 80% задач с массивами

главное
  • 01map → новый массив той же длины, каждый элемент преобразован
  • 02filter → новый массив, только те где условие true
  • 03reduce → одно значение из массива (сумма, объект, что угодно)
  • 04Цепочки — естественный способ комбинировать: filter → map → reduce
  • 05Все три НЕ меняют исходный массив — возвращают новый
  • 06reduce имеет начальное значение вторым аргументом — почти всегда нужно его указывать
  • 07В React при рендере списка — почти всегда .map: items.map(i => <Item ... />)
проверь себя
01`[1, 2, 3, 4].filter(n => n > 2).map(n => n * 10)` — что вернёт?
02У вас массив users с полями age. Какой код считает количество совершеннолетних?
03Что обязательно нужно вернуть из функции map?
следующий урок: Модули — import и export