reduce
map и filter возвращают массив, а сумма, максимум или количество — это одно значение. Для таких задач на конвейере нужна не вторая лента, а копилка.
Представьте работника с копилкой у ленты. Перед началом он кладёт в копилку стартовую сумму, например ноль. Каждый подъехавший ящик он вскрывает, добавляет его содержимое к деньгам из копилки и кладёт всё обратно. Когда лента опустеет, в копилке окажется итог.
Метод reduce работает так же: он проходит по массиву и собирает все элементы в одно значение.
const nums = [4, 7, 10];
const sum = nums.reduce((total, n) => total + n, 0);
console.log(sum); // 21Давайте разберём вызов по частям:
(total, n) => total + n— колбэк, наш работник: он берёт деньги из копилкиtotalи очередной ящикn.0— стартовая сумма в копилке.reduceвозвращает то, что оказалось в копилке в конце, и программа печатает21.
На собеседовании часто просят посчитать сумму массива через reduce. Этот пример и есть ответ.
Аккумулятор
reduce принимает два аргумента: колбэк и начальное значение, здесь 0. Колбэк получает промежуточный результат и очередной элемент, а возвращает новый промежуточный результат. Промежуточный результат называют аккумулятором; в примере это параметр total.
Имена параметров колбэка выбирают сами: total и n подсказывают читателю, что хранит каждый из них.
Как идут вызовы
Аккумулятор переходит от вызова к вызову по трём правилам:
- При первом вызове аккумулятор равен начальному значению.
- Каждый следующий вызов получает то, что вернул предыдущий.
- Что вернул последний вызов, то и возвращает
reduce.
Для [4, 7, 10] вызовы идут так:
total | n | колбэк возвращает |
|---|---|---|
0 | 4 | 4 |
4 | 7 | 11 |
11 | 10 | 21 |
Нажимайте «Следующий шаг» и следите за total: каждый новый вызов add получает число, которое вернул предыдущий. Колбэк в программе виджета — именованная функция add, чтобы у каждого её вызова была своя рамка. Между рамками script и add лежит рамка самого reduce: метод — тоже функция, он хранит аккумулятор и сам вызывает add для каждого элемента.
1const nums = [4, 7, 10];2 3function add(total, n) {4 const next = total + n;5 return next;6}7 8const sum = nums.reduce(add, 0);9console.log(sum);
Скрипт вызывает reduce и передаёт ему колбэк add и начальное значение 0.
Начальное значение выбирают так, чтобы оно не испортило результат: для суммы это 0, для произведения — 1. reduce не меняет исходный массив.
Не только сумма
Здесь аналогия с копилкой заканчивается. В копилке лежат только деньги, а аккумулятор может хранить любое значение: максимум, счётчик, строку.
Максимум
Чтобы найти максимум, колбэк сравнивает элемент с лучшим найденным и возвращает большее из двух. Начальным значением здесь служит первый элемент.
const temps = [12, 31, 18];
const max = temps.reduce((best, t) => (t > best ? t : best), temps[0]);
console.log(max); // 31Число 0 для максимума не годится. Если все числа отрицательные, результатом окажется 0, которого в массиве нет.
Счётчик
Аккумулятор бывает и счётчиком. Вызов words.reduce((count, w) => (w.length > 3 ? count + 1 : count), 0) считает слова длиннее трёх букв. Колбэк здесь возвращает либо увеличенный счётчик, либо прежний.
Без начального значения
Начальное значение можно не передавать. Тогда аккумулятором становится первый элемент, а колбэк вызывается со второго: nums.reduce((total, n) => total + n) тоже даёт 21.
Частая ошибка
Начальное значение не передали, а массив оказался пустым:
const empty = [];
const total = empty.reduce((sum, n) => sum + n); // ✗TypeError: Reduce of empty array with no initial valueБез начального значения reduce берёт аккумулятор из первого элемента, а в пустом массиве его нет. Передайте начальное значение: empty.reduce((sum, n) => sum + n, 0) возвращает 0, и колбэк не вызывается ни разу. С начальным значением reduce работает с массивом любой длины.
Главное
reduceсобирает все элементы массива в одно значение — аккумулятор.- Первый вызов колбэка получает начальное значение, каждый следующий — то, что вернул предыдущий.
reduceвозвращает результат последнего вызова и не меняет исходный массив.- Без начального значения
reduceна пустом массиве останавливает программу сTypeError.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.