Возврат массивов и объектов из метода reduce()
reduce()
На данный момент вы, скорее всего, уже знакомы с большинством методов работы с массивами, особенно с методами map()
, filter()
и reduce()
. Однако вы, вероятно, не знали, что некоторые вещи, которые вы первоначально делали с помощью методов map()
и filter()
, можно также сделать с помощью метода reduce()
. Мы можем возвращать из метода reduce()
массивы и даже объекты, а также использовать его в качестве счётчика, в зависимости от того, для какой задачи он нужен. Не теряя времени, давайте рассмотрим некоторые из этих сценариев, в которых может пригодиться метод reduce()
.
Использование reduce()
вместо filter()
Предположим, что нам дан массив ages
, содержащий возрасты разных людей, и требуется составить массив из возрастов, которые попадают в возраст, необходимый для получения водительских прав (т.е. ages >= 18
). Обычно это делается с помощью метода filter()
следующим образом;
const ages = [14, 19, 16, 23, 12, 38, 20, 17, 10, 18];
const legalAge = ages.filter((el) => el >= 18);
console.log(legalAge); // Результат [19, 23, 38, 20, 18]
Результат функции legalAge
возвращает массив возрастов, удовлетворяющих возрастному критерию, необходимому для получения водительских прав (возраст больше или равен 18 годам). Однако мы можем проделать то же самое, что и выше, используя метод reduce()
, и получить тот же результат.
const ages = [14, 19, 16, 23, 12, 38, 20, 17, 10, 18];
const ageLegal = ages.reduce((acc, el) => {
if (el >= 18) acc.push(el);
return acc;
}, []);
console.log(ageLegal); // Результат [19, 23, 38, 20, 18]
Для этого нам потребуется функция, а также инициализация нашего аккумулятора (acc
) в виде массива. Затем в методе reduce()
мы зададим условие, помещающее текущий элемент итерации в массив аккумуляторов (acc
) только в том случае, если он больше или равен "18", а также явно вернём наш аккумулятор (поскольку в теле функции аккумулятор не возвращается автоматически).
Использование reduce()
вместо map()
Предположим, что нам дан массив значений, затем нужно разделить значения этого массива на два и сохранить результат в новом массиве, мы можем сделать это с помощью метода map()
таким образом;
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const arrHalf = arr.map((el) => el / 2);
console.log(arrHalf);
// Результат [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5]
В качестве альтернативы можно также использовать метод reduce()
для решения задачи следующим образом;
const halfRed = arr.reduce((acc, el) => {
acc.push(el / 2);
return acc;
}, []);
console.log(halfRed);
// Результат [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5]
Мы инициализируем аккумулятор как пустой массив, а затем на каждой итерации помещаем в массив текущий элемент, делённый на два, аккумулятор также явно возвращается.
Возврат объекта из метода reduce()
Предположим, что нам дан массив, содержащий набор транзакций (снятия и пополнения), и мы должны на основе этого массива создать объект, содержащий свойства deposit
и withdraw
. Как это сделать с помощью метода reduce()
;
const transactions = [-100, 200, 350, -400, -10, 30, -8, 120, 20];
const transactionObj = transactions.reduce(
(acc, el) => {
el < 0 ? (acc.withdrawals += el) : (acc.deposits += el);
return acc;
},
{ deposits: 0, withdrawals: 0 }
);
console.log(transactionObj);
// Результат {deposits: 720, withdrawals: -518}
Наш аккумулятор инициализируется как объект, содержащий свойства deposit
и withdrawals
, причём оба они имеют начальные значения, равные нулю. Затем на каждой итерации, используя тернарный оператор, мы добавляем текущее значение массива к свойствам deposit
или withdrawals
в зависимости от того, больше оно (т.е. текущее значение) нуля или нет. Наконец, мы также явно возвращаем наш объект аккумулятор.
Подсчёт с помощью метода reduce()
Если предположить, что нам нужно подсчитать количество депозитов в массиве transactions
(т.е. Транзакции больше нуля), то, не задумываясь, мы можем использовать метод filter()
для фильтрации значений больше нуля и просто взять длину возвращаемого массива, как показано ниже;
const transactions = [-100, 200, 350, -400, -10, 30, -8, 120, 20];
const numDeposits = transactions.filter((el) => el > 0).length;
console.log(numDeposits); // Результат 5
Как видно из вышеприведённого, numDeposits
возвращает значение 5
, которое является результатом количества депозитов в массиве transactions
. В качестве альтернативы можно использовать метод reduce()
, например, так;
const transactions = [-100, 200, 350, -400, -10, 30, -8, 120, 20];
const depositsNum = transactions.reduce((acc, el) => (el > 0 ? ++acc : acc)
, 0);
console.log(depositsNum); // Результат 5
В приведённом выше методе аккумулятор инициализируется равным 0
, а затем на каждой итерации с помощью тернарного оператора мы добавляем в аккумулятор единицу, если текущий элемент больше нуля, и возвращаем аккумулятор с предыдущей итерации, если текущий элемент меньше нуля. Обратите внимание, что вместо acc++
мы использовали ++acc
, так как прямое возвращение acc++
не даёт желаемого результата, поскольку в каждой итерации будет возвращаться 0
.
Заключение
Данная статья ни в коем случае не ставит своей целью убедить читателя отказаться от традиционных методов выполнения операций над массивами, к которым он уже привык. Напротив, она призвана показать читателям другие удобные способы выполнения операций над массивами в JavaScript с помощью метода reduce()
, а также продемонстрировать несколько расширенных (нетрадиционных) функциональных возможностей, которые могут быть реализованы с помощью метода reduce()
. Спасибо за внимание.