reduce: самый мощный метод массивов
reduce — это «свёртка» массива в одно значение. Звучит просто, но за этим скрывается невероятная мощь. Сумма, произведение, максимум, группировка, преобразование в объект — всё это reduce.
🧠 Идея: сворачиваем массив в одно значение
Все методы, которые мы изучали раньше, работают «один к одному»: map из массива даёт массив той же длины, filter — массив меньшей длины. А reduce из всего массива делает одно значение. Любое: число, строку, объект, другой массив.
Аналогия: представьте снежный ком, который катится с горы и собирает снег. Снег — это элементы массива. Ком нарастает с каждым шагом — это аккумулятор. В конце у вас один большой ком — это результат reduce.
Синтаксис:
array.reduce(function(accumulator, currentValue) {
return /* новое значение аккумулятора */;
}, initialValue);
Четыре участника:
- accumulator (аккумулятор) — «бегущий итог», который накапливается с каждым шагом
- currentValue (текущее значение) — элемент массива, который обрабатывается прямо сейчас
- колбэк — функция, которая получает аккумулятор и текущий элемент, возвращает новый аккумулятор
- initialValue (начальное значение) — с чего начинается аккумулятор
💡 Всегда указывайте initialValue! Без него reduce использует первый элемент как начальное значение аккумулятора — это работает, но может привести к неожиданным результатам, особенно с пустыми массивами или объектами.
👣 Как работает reduce: шаг за шагом
Разберём на простейшем примере — сумме чисел. Посмотрим, что происходит на каждой итерации:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // → 15
| Шаг | accumulator (acc) | currentValue (cur) | acc + cur (новый acc) |
|---|---|---|---|
| Старт | 0 (initialValue) | — | — |
| 1 | 0 | 1 | 1 |
| 2 | 1 | 2 | 3 |
| 3 | 3 | 3 | 6 |
| 4 | 6 | 4 | 10 |
| 5 (финал) | 10 | 5 | 15 ✓ |
Видите? На каждом шаге аккумулятор «вбирает» в себя следующий элемент. Это и есть «свёртка» — у вас было 5 чисел, а стало одно.
🛠️ Практические примеры
➕ Сумма и произведение
const nums = [2, 3, 4, 5];
// Сумма
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum); // → 14
// Произведение
const product = nums.reduce((acc, n) => acc * n, 1);
console.log(product); // → 120 (2*3*4*5)
// Заметьте: начальное значение для произведения — 1, а не 0!
🏆 Максимум и минимум
const temps = [12, 7, 25, 3, 18];
// Максимум
const max = temps.reduce((acc, cur) => cur > acc ? cur : acc, -Infinity);
console.log(max); // → 25
// Минимум
const min = temps.reduce((acc, cur) => cur < acc ? cur : acc, Infinity);
console.log(min); // → 3
// Или через Math.max / Math.min
const max2 = temps.reduce((acc, cur) => Math.max(acc, cur), -Infinity);
console.log(max2); // → 25
📂 Группировка по свойству
const people = [
{ name: "Алиса", city: "Москва" },
{ name: "Боб", city: "Питер" },
{ name: "Карл", city: "Москва" },
{ name: "Диана", city: "Казань" },
{ name: "Ева", city: "Питер" }
];
// Сгруппировать по городу
const byCity = people.reduce((acc, person) => {
const city = person.city;
// Если в аккумуляторе ещё нет этого города — создаём пустой массив
if (!acc[city]) {
acc[city] = [];
}
// Добавляем человека в группу его города
acc[city].push(person.name);
return acc;
}, {}); // Начальное значение — пустой объект
console.log(byCity);
// → {
// "Москва": ["Алиса", "Карл"],
// "Питер": ["Боб", "Ева"],
// "Казань": ["Диана"]
// }
🔄 Преобразование массива в объект
// Задача: превратить массив объектов в словарь по id
const users = [
{ id: 1, name: "Алиса" },
{ id: 2, name: "Боб" },
{ id: 3, name: "Карл" }
];
const usersById = users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {});
console.log(usersById);
// → { 1: { id: 1, name: "Алиса" }, 2: {...}, 3: {...} }
// Теперь быстрый доступ по id
console.log(usersById[2].name); // → "Боб"
// Это в разы быстрее, чем каждый раз делать find!
🎯 reduce = map + filter + любой результат. Технически через reduce можно реализовать любой другой метод массива. Он — самый универсальный. Но это не значит, что всегда нужно использовать именно его: map и filter читаются понятнее. Используйте reduce, когда нужен нестандартный результат.
🛒 Реальный кейс: подсчёт стоимости корзины
const cart = [
{ name: "Ноутбук", price: 80000, qty: 1 },
{ name: "Мышь", price: 1500, qty: 2 },
{ name: "Клавиатура", price: 3000, qty: 1 },
{ name: "Наушники", price: 8000, qty: 1 }
];
// Подсчёт общей суммы
const total = cart.reduce((acc, item) => {
return acc + item.price * item.qty;
}, 0);
console.log(`Итого: ${total.toLocaleString()} ₽`);
// → "Итого: 92 500 ₽"
// Количество позиций (штук)
const totalQty = cart.reduce((acc, item) => acc + item.qty, 0);
console.log(`Товаров: ${totalQty} шт.`); // → "Товаров: 5 шт."
// Самый дорогой товар
const mostExpensive = cart.reduce((acc, item) => {
return item.price > acc.price ? item : acc;
}, cart[0]);
console.log(`Самый дорогой: ${mostExpensive.name}`);
// → "Самый дорогой: Ноутбук"
✅ Итоги урока
reduce(callback, initialValue)— «сворачивает» массив в одно значение любого типа- Колбэк получает accumulator (накопленный итог) и currentValue (текущий элемент)
- Что вернул колбэк — то становится новым аккумулятором на следующем шаге
- Всегда указывайте initialValue — это делает код предсказуемым
- Начальное значение зависит от задачи: для суммы —
0, для произведения —1, для объекта —{}, для массива —[] - reduce умеет группировать, преобразовывать в объект, искать максимум/минимум
- Технически через reduce можно реализовать любой другой метод массивов
В следующем уроке — sort() с компаратором: почему массив чисел сортируется «неправильно» по умолчанию и как это исправить. 🔢
reduce — свёртка массива
6 вопросов