JavaScript | Array | reduce

JavaScript | Array | reduce

Логика работы метода reduce() в JavaScript

Метод reduce() обойдёт все элементы оригинального массива от начала и до конца. Метод двигается слева направо. Каждый вызов первого параметра метода (коллбэк), сокращает новый массив на один элемент — сокращает на первый элемент. То есть на каждом вызове метода будет уменьшаться длина нового массива. Возвращаемое значение первого параметра всегда будет первым элементом нового массива. И будет переназначаться каждый раз для каждого вызова коллбэка.

 

Пример работы

reduce() с первым параметром, а коллбэк с двумя параметрами

var m = ["aa","bb","cc","dd","ee","ff"]

m.reduce((a,b)=>a+b)
"aabbccddeeff"
reduce с 1 параметром на массиве из строк - коллбэк 2 параметра - JavaScript
reduce с 1 параметром на массиве из строк — коллбэк 2 параметра — JavaScript

Если приглядеться в итоговый результат, то это очень похоже на вызов метода join(«») с параметром в виде пустой строки. Каждый элемент массива склеился в хронологическом порядке. В результате образовалась одна длинная строка.

В этом примере произошла пошаговая конкатенация строк. Давайте посмотрим на вызовы коллбэка и то как менялся массив:

вызов 1 вернёт
"aabb"

["aabb","cc","dd","ee","ff"]

вызов 2 вернёт
"aabbcc"

["aabbcc","dd","ee","ff"]

вызов 3 вернёт
"aabbccdd"

["aabbccdd","ee","ff"]

вызов 4 вернёт
"aabbccddee"

["aabbccddee","ff"]

вызов 5 вернёт
"aabbccddeeff"

["aabbccddeeff"]

У нас 6 элементов, но вызовов было 5, потому что сравниваются пары предыдущего значения и следующего — их будет 5.

 

В чём тут плюс? Мы можем очень быстро перевернуть результат, если это необходимо.

var m = ["aa","bb","cc","dd","ee","ff"]

m.reduce((a,b)=>b+a)
"ffeeddccbbaa"

Если бы использовали join(), то нужно было бы добавлять перед ним reverse()

[].concat(m).reverse().join("")
"ffeeddccbbaa"
Альтернатива методу join отражение массива - JavaScript
Альтернатива методу join отражение массива — JavaScript

 

Если мы будем работать с массивом из чисел, то такая команда вернёт нам сумму всех значений элементов массива.

var m1 = [2,8,4,6,5,5]

m1.reduce((a,b)=>b+a)
или
m1.reduce((a,b)=>a+b)

Результат работы

Сложение всех чисел элементов массива методом reduce - JavaScript
Сложение всех чисел элементов массива методом reduce — JavaScript

reduce() с первым параметром, а коллбэк с тремя параметрами

Третьим параметром коллбэка будет индекс массива.

var m = ["aa","bb","cc","dd","ee","ff"]

m.reduce((a,b,c)=>c+a)
"54321aa"

m.reduce((a,b,c)=>c+b)
"5ff"

m.reduce((a,b,c)=>c+a+b)
"54321aabbccddeeff"

m.reduce((a,b,c)=>c+b+a)
"5ff4ee3dd2cc1bbaa"

 

reduce() с первым параметром, а коллбэк с четырьмя параметрами

Четвёртым параметром коллбэка будет просматриваемый объект, по которому совершается обход.

var m = ["aa","bb","cc","dd","ee","ff"]

m.reduce((a,b,c,e)=>c+a+e.length)
"54321aa66666"

или

["aa","bb","cc","dd","ee","ff"].reduce((a,b,c,e)=>c+a+e.length)
"54321aa66666"

Мы задействовали сам массив и его свойство length, которое обозначает длину массива.

Можно использовать все четыре параметра в возвращаемом значении

m.reduce((a,b,c,e)=>c+b+a+e.length)
"5ff4ee3dd2cc1bbaa66666"

Array.prototype.reduce ( callbackfn [ , initialValue ] )

Примечание 1

callbackfn должен быть функцией, которая принимает четыре аргумента. reduce вызывает callbackfn (обратный вызов) как функцию один раз для каждого элемента после первого элемента, присутствующего в массиве, в порядке возрастания.

callbackfn вызывается с четырьмя аргументами: previousValue (значение из предыдущего вызова callbackfn), currentValue (значение текущего элемента), currentIndex и просматриваемый объект, по которому совершается обход. При первом вызове этого обратного вызова previousValue и currentValue могут быть одним из двух значений:

  • Если в вызове для уменьшения reduce было указано initialValue, то previousValue будет равно initialValue, а currentValue будет равно первому значению в массиве.
  • Если значение initialValue не было указано, то previousValue будет равно первому значению в массиве, а currentValue будет равно второму. Это ошибка TypeError, если массив не содержит элементов и не указано initialValue.

reduce не изменяет напрямую объект, для которого он вызывается, но объект может быть изменен вызовами callbackfn.

Диапазон элементов, обрабатываемых с помощью reduce, устанавливается перед первым вызовом callbackfn. Элементы, которые добавляются к массиву после начала вызова reduce, не будут посещаться callbackfn. Если существующие элементы массива изменены, их значение, переданное в callbackfn, будет значением на момент их посещения командой reduce; элементы, которые удаляются после начала вызова reduce и до посещения, не посещаются.

 

Когда метод reduce вызывается с одним или двумя аргументами, выполняются следующие шаги:

1. Пусть O будет ? ToObject(значение this)
2. Пусть len будет ? LengthOfArrayLike(O)
3. Если IsCallable(callbackfn) имеет значение false, генерировать исключение TypeError.
4. Если len = 0 и initialValue отсутствует, выбросить исключение TypeError.
5. Пусть k равно 0.
6. Пусть accumulator не определен - undefined.
7. Если присутствует initialValue, то
   a. Установите accumulator на initialValue.
8. Иначе,
   a. Пусть kPresent ложно false.
   b. Повторите, пока kPresent имеет значение false и k < len,
      i. Пусть Pk будет ! ToString(𝔽(k)).
      ii. Установите для kPresent значение ? HasProperty(O, Pk).
      iii. Если kPresent истинно true, то
         1. Установить accumulator на ? Get(O, Pk).
      iv. Установите k на k + 1.
   c. Если kPresent имеет значение false, выбросить исключение TypeError.
9. Повторить, пока k < len,
   a. Пусть Pk будет ! ToString(𝔽(k)).
   b. Пусть kPresent будет ? HasProperty(O, Pk).
   c. Если kPresent истинно true, то
      i. Пусть kValue будет ? Get(O, Pk).
      ii. Установить accumulator на ? Call(callbackfn, undefined, «accumulator, kValue, 𝔽(k), O»).
   d. Установите k на k + 1.
10. Вернуть accumulator

Примечание 2

Функция reduce намеренно универсальна; она не требует, чтобы значение this было объектом массива. Поэтому его можно передать другим видам объектов для использования в качестве метода.

 

Информационные ссылки

JavaScript | Массивы (Array)

Стандарт ECMAScript — Раздел «23.1.3.21 Array.prototype.reduce ( callbackfn [ , initialValue ] )» — https://tc39.es/ecma262/#sec-array.prototype.reduce