Знаете ли вы, что на самом деле вы можете использовать тот же метод reduce, который вы всегда использовали для возврата суммы для объединения в цепочку ваших обещаний или даже для составления функций?
Метод reduce является одним из самых мощных методов работы с массивами, используемых в JavaScript, наряду с другими мстителями — методом filter и map.
Его мощь также означает, что он редко понимается начинающими разработчиками вроде меня и почти не используется основными разработчиками JavaScript.
Сегодня мы рассмотрим его традиционное применение для суммирования значений, а также два более интересных случая использования, которые мы рассмотрим далее в статье.
Что такое метод Reduce?
Согласно MDN
Метод reduce() выполняет предоставленную пользователем функцию обратного вызова «reducer» на каждом элементе массива по порядку, передавая возвращаемое значение из вычисления на предыдущем элементе.
Подобно map, filter и forEach, метод reduce позволяет нам итерационно просматривать наш массив, выполняя функцию обратного вызова для каждого элемента и возвращая одно значение.
Интересно, что это единственное значение может быть любым — числом, массивом или даже объектом.
1. Функция накопителя
Очевидно, что это самый распространенный пример, известный человеку!
Сказать, что он распространен, можно относительно, но это, наверное, самый простой пример использования метода reduce в Интернете.
Допустим, у нас есть массив объектов, и мы хотим получить сумму зарплат, чтобы решить, почему стажер получает $30, а начальник — $400.
// Array of objects
const staff = [
{name: 'bob', age: 20, position: 'developer', salary: 100},
{name: 'peter', age: 25, position: 'designer', salary: 300},
{name: 'susy', age: 30, position: 'CEO', salary: 400},
{name: 'anna', age: 35, position: 'intern', salary: 30}
]
Вот один из способов использования метода reduce:
const totalSalary = staff.reduce((total, currSalary) => {
total = total + currSalary.salary
return total
}, 0)
NB: Всегда возвращайте первый параметр!
Здесь мы создаем новую переменную с именем totalSalary
и используем метод reduce, который принимает два параметра — total, currSalary.
Теперь эти два параметра могут быть названы как угодно, но по сути, это аккумуляторы — total
и currSalary
обозначают сумму итерации и текущий элемент, который итерируется в данный момент времени соответственно.
Параметр total
существует для хранения суммы каждого цикла итерации, а currSalary
определяет следующий элемент цикла, по которому будет выполняться итерация.
Мы также должны определить начальную позицию нашего цикла, поэтому в конце нашей функции обратного вызова стоит 0, с которого начинается наш подсчет.
В сущности, вот что мы получаем в результате выполнения вышеприведенной функции:
// console.log(total); 0, 100, 400, 800, 830
// console.log(currSalary.salary); 100, 300, 400, 30
console.log(totalSalary), // 830
И вот так, практически без кода, у вас есть сумма выплаченной сотрудникам зарплаты.
Однако дальше все становится интереснее 🙂
Больше методов уменьшения…
Если вы знали и использовали reduce только для возврата суммы значений в массиве, то загляните в это место, чтобы увидеть немного волшебства!
2. Объединение обещаний в цепочку
Ключевое слово async при управлении долгоиграющими задачами, возможно, лучшее, что когда-либо случалось с JavaScript.
Оно помогает нам группировать отдельные задачи в функции, которые могут быть переданы в следующую функцию.
Но как быть в ситуации, когда вы собираетесь использовать что-то помимо ключевого слова async и хотите получить чистый код, лишенный популярного ада обратных вызовов.
Использование метода reduce в вашей функции может быть вариантом достижения той же цели и в конечном итоге поможет вам управлять различными фазами каждой итерации задачи?
Допустим, у нас есть локальный api, содержащий некоторые идентификаторы:
let itemIDs = [1, 2, 3, 4, 5]
Один из способов связать наши обещания в цепочку без использования обычной функции .then
заключается в следующем:
const itemSum = itemIDs.reduce(async (promise, itemID) => {
const item = await promise
return item.deleteItem(itemID)
}, Promise.resolve())
Теперь, по сути, то, что мы делаем, это не более чем обычная цепочка команд .then, например, такая:
Promise.resolve()
.then((item) => item.deleteItem(1))
.then((item) => item.deleteItem(2))
.then((item) => item.deleteItem(3))
.then((item) => item.deleteItem(4))
.then((item) => item.deleteItem(5))
3. Компоновка функций
Метод reduce также можно использовать для компоновки наших функций, то есть определить, как и в каком направлении мы хотим, чтобы работала итерация.
Метод reduce известен тем, что действует как аккумулятор, но его фишка в том, что он всегда сортирует массив слева направо.
Как насчет того, чтобы определить это по-своему, составив функцию с помощью reduce() и передав результат следующей выполняющейся функции?
Этот пример я позаимствовал у Бояна Гвоздерака и его статьи о методах reduce, filter и map.
У нас может получиться что-то интересное;
let double = [1, 2, 3, 4, 5]
const compose =
(...double) =>
(n) =>
double.reduceRight((v, f) => f(v), n)
Вот это действительно умопомрачительная вещь, которую мне было довольно трудно понять.
Но вот в чем фокус:
У нас есть переменная compose — которая частично применяется с помощью параметра rest, так что мы можем составить столько функций, сколько захотим, и все они будут помещены в массив double
.
Далее мы передаем начальное значение n
, после чего используем reduceRight
вместе с начальным значением n
для определения начальной позиции или составленной функции.
Может возникнуть путаница, но это то же самое, что и метод reduce
в первом примере, только аккумулятор начинает отсчет с конца массива, а затем перемещается к началу с помощью параметра (f, v)
.
Потрясающая путаница!
Заключение
Метод reduce — это адский метод, который можно использовать разными способами и с JavaScript без определенной структуры, как вам кажется…
Однако удивительно то, что он передает результат функции обратного вызова следующей, позволяя нам манипулировать данными массива различными способами.
Итак, мы рассмотрели действительно удивительные случаи использования метода reduce, а также эффективную практику для работы с данными Api.
Однако я хотел бы узнать, какие из этих методов вы уже применяли в своих проектах.
Кроме того, если вы знаете другие интересные и креативные способы использования метода reduce, я буду рад узнать о них в комментариях😊.
Если вам понравилась эта статья, подпишитесь на меня, а также заходите на мой Twitter, так как я веду вас по пути изучения JavaScript для фронтенд-разработки.
https://github.com/trillionclues
Спасибо, что прочитали! ❤️