В этом руководстве вы узнаете, как использовать перебирающие методы JavaScript Array reduce()
и reduceRight()
для преобразования и сокращения массива до значения.
Предположим, что у вас есть массив чисел, например:
let numbers = [1, 2, 3];
и вы хотите вычислить общее количество элементов массива.
Как правило, вы используете цикл for в Javascript для перебора элементов и их добавления, как показано в следующем примере:
let numbers = [1, 2, 3]; let sum = 0; for(let i = 0; i < numbers.length; i++) { sum += numbers[i]; } console.log(sum);
Выход:
6
Скрипт прост и понятен:
- Сначала объявите массив из трех чисел 1, 2 и 3.
- Во-вторых, объявите переменную
sum
и установите ее значение равным нулю. - В-третьих, в цикле
for
добавьте элементы массиваnumbers
к переменнойsum
. После цикла значение переменнойsum
равно 6.
Что мы сделали, так это преобразовали массив в значение.
Array.prototype
позволяет уменьшить массив до одного значения с помощью метода reduce()
следующим образом:
let numbers = [1, 2, 3]; let sum = numbers.reduce(function(previousValue, currentValue) { return previousValue + currentValue; }); console.log(sum);
Это довольно просто, не так ли?
Давайте подробно рассмотрим метод reduce()
.
Подробное описание
Ниже показан синтаксис метода reduce()
:
array.reduce(callbackFn [, initialValue])
Метод reduce()
принимает два аргумента:
- Функция обратного вызова
callbackFn
. Эту функцию часто называют редуктором. - Необязательное начальное значение.
Метод вызывает callbackFn()
для каждого элемента массива.
Функция reducer()
возвращает значение, полученное в результате выполнения callbackFn
до завершения всего массива.
1) Аргумент функции callbackFn()
Функция callbackFn
имеет следующий синтаксис:
function callbackFn(previousValue, currentValue, currentIndex, array) { /**/}
Функция callbackFn
принимает четыре аргумента:
previousValue
. Значение, возвращенное предыдущим вызовом функцииcallbackFn
. При первом вызовеinitialValue
являетсяpreviousValue
значением, если вы передаетеinitialValue
. В противном случае его значение равноarray[0]
.currentValue
. Значение текущего элемента массива. При первом вызове этоarray[0]
, если выinitialValue
илиarray[1]
в противном случае.currentIndex
. ИндексcurrentValue
в массиве. При первом вызове это0
, если вы передаете initialValue или 1 в противном случае.array
. Массив для цикла.
2) Аргумент начального значения
Аргумент initialValue
является необязательным.
Если вы укажете initialValue
, функция callbackFn
инициализирует previousValue
значение значением initialValue
а currentValue
значение — первым элементом массива при первом вызове.
Если вы не укажете initialValue
, функция callbackFn
инициализирует previousValue
значение для первого элемента массива( array[0]
) в массиве и currentValue
для второго элемента массива( array[1]
).
Следующая таблица иллюстрирует логику, когда метод reduce()
выполняет callbackFn()
в первый раз в соответствии с аргументом initialValue
:
initialValue | previousValue | currentValue |
---|---|---|
Прошло | initialValue | array[0] |
Не прошло | array[0] | array[1] |
В следующем примере показан ход выполнения функции reduce() с initialValue
значением, равным 100:
let numbers = [1, 2, 3]; function getOrdinalSuffix(i) { let j = i % 10, k = i % 100; if (j == 1 && k != 11) return i + 'st'; if (j == 2 && k != 12) return i + 'nd'; if (j == 3 && k != 13) return i + 'rd'; return i + 'th'; } let call = 1; let sum = numbers.reduce(function (previousValue, currentValue, currentIndex, array) { let result = previousValue + currentValue; // show the 1st call, 2nd call, etc. console.log(`${getOrdinalSuffix(call)} call`); call++; // show the immediate values console.table({ previousValue, currentValue, currentIndex, result }); return result; },100); console.log(`Result: ${sum}`);
Выход:
1st call ┌───────────────┬────────┐ │ (index) │ Values │ ├───────────────┼────────┤ │ previousValue │ 100 │ │ currentValue │ 1 │ │ currentIndex │ 0 │ │ result │ 101 │ └───────────────┴────────┘ 2nd call ┌───────────────┬────────┐ │ (index) │ Values │ ├───────────────┼────────┤ │ previousValue │ 101 │ │ currentValue │ 2 │ │ currentIndex │ 1 │ │ result │ 103 │ └───────────────┴────────┘ 3rd call ┌───────────────┬────────┐ │ (index) │ Values │ ├───────────────┼────────┤ │ previousValue │ 103 │ │ currentValue │ 3 │ │ currentIndex │ 2 │ │ result │ 106 │ └───────────────┴────────┘ Result: 106
А следующий пример иллюстрирует метод reduce()
без аргумента initialValue
:
1st call ┌───────────────┬────────┐ │ (index) │ Values │ ├───────────────┼────────┤ │ previousValue │ 1 │ │ currentValue │ 2 │ │ currentIndex │ 1 │ │ result │ 3 │ └───────────────┴────────┘ 2nd call ┌───────────────┬────────┐ │ (index) │ Values │ ├───────────────┼────────┤ │ previousValue │ 3 │ │ currentValue │ 3 │ │ currentIndex │ 2 │ │ result │ 6 │ └───────────────┴────────┘ Result: 6
Дополнительные примеры
Предположим, у вас есть следующий массив объектов товаров shoppingCart
:
let shoppingCart = [ { product: 'phone', qty: 1, price: 500, }, { product: 'Screen Protector', qty: 1, price: 10, }, { product: 'Memory Card', qty: 2, price: 20, }, ];
Чтобы рассчитать общее количество продуктов в корзине, вы можете использовать метод reduce()
, например:
let total = shoppingCart.reduce(function(previousValue, currentValue) { return previousValue + currentValue.qty * currentValue.price; }, 0);
Выход:
550
Обратите внимание, что в этом примере мы передали аргумент initialValue
reduce()
.
Если бы мы этого не сделали, метод reduce()
принял бы первый элемент массива shoppingCart
, который является объектом, в качестве начального значения и выполнил бы вычисление для этого объекта. Следовательно, это приведет к неправильному результату.
Метод reduceRight()
Метод reduceRight()
работает так же, как и метод reduce()
, но в обратном направлении.
Метод начинается с первого элемента и перемещается к последнему, тогда как метод reduceRight()
начинается с последнего элемента и перемещается назад к первому.
Пример:
let numbers = [1, 2, 3]; let sum = numbers.reduceRight(function(previousValue, currentValue) { console.log({ previousValue, currentValue }); return previousValue + currentValue; }); console.log(`Result:${sum}`);
Выход
{ previousValue: 3, currentValue: 2 } { previousValue: 5, currentValue: 1 } Result:6
На следующем рисунке показана разница между методами reduce()
и reduceRight()
: