Книга: JavaScript. Подробное руководство, 6-е издание
7.9.5. Методы reduce() и reduceRight()
7.9.5. Методы reduce() и reduceRight()
Методы reduce()
и reduceRight()
объединяют элементы массива, используя указанную вами функцию, и возвращают единственное значение. Это типичная операция в функциональном программировании, где она известна также под названием «свертка». Примеры ниже помогут понять суть этой операции:
var а = [1,2,3,4,5]
var sum = a.reduce(function(x,у) { return х+у }, 0); // Сумма значений
var product = a.reduce(function(x,у) { return х*у }, 1); // Произвел, значений
var max = a.reduce(function(x,у) { return (х>у)?х:у; }); // Наибольш. значение
Метод reduce()
принимает два аргумента. В первом передается функция, которая выполняет операцию свертки. Задача этой функции - объединить некоторым способом или свернуть два значения в одно и вернуть свернутое значение. В примерах выше функции выполняют объединение двух значений, складывая их, умножая и выбирая наибольшее. Во втором (необязательном) аргументе передается начальное значение для функции.
Функции, передаваемые методу reduce()
, отличаются от функций, передаваемых методам forEach()
и map().
Знакомые уже значение, индекс и массив передаются им во втором, третьем и четвертом аргументах. А в первом аргументе передается накопленный результат свертки. При первом вызове в первом аргументе функции передается начальное значение, переданное методу reduce() во втором аргументе. Во всех последующих вызовах передается значение, полученное в результате предыдущего вызова функции. В первом примере, из приведенных выше, функция свертки сначала будет вызвана с аргументами 0 и 1. Она сложит эти числа и вернет 1. Затем она будет вызвана с аргументами 1 и 2 и вернет 3. Затем она вычислит 3+3=6, затем 6+4=10 и, наконец, 10+5=15. Это последнее значение 15 будет возвращено методом reduce().
Возможно, вы обратили внимание, что в третьем вызове, в примере выше, методу reduce()
передается единственный аргумент: здесь не указано начальное значение. Когда метод reduce()
вызывается без начального значения, как в данном случае, в качестве начального значения используется первый элемент массива. Это означает, что при первом вызове функции свертки будут переданы первый и второй элементы массива. В примерах вычисления суммы и произведения точно так же можно было бы опустить аргумент с начальным значением.
Вызов метода reduce()
с пустым массивом без начального значения вызывает исключение ТуреЕrror
. Если вызвать метод с единственным значением - с массивом, содержащим единственный элемент, и без начального значения или с пустым массивом и начальным значением - он просто вернет это единственное значение, не вызывая функцию свертки.
Метод reduceRight()
действует точно так же, как и метод reduce(), за исключением того, что массив обрабатывается в обратном порядке, от больших индексов к меньшим (справа налево). Это может потребоваться, если операция свертки имеет ассоциативность справа налево, например:
var а = [2, 3, 4]
// Вычислить 2^(3^4). Операция возведения в степень имеет ассоциативность справа налево
var big = a.reduceRight(function(accumulator,value) {
return Math.pow(value,accumulator);
});
Обратите внимание, что ни reduce(),
ни reduceRight()
не принимают необязательный аргумент, определяющий значение this
внутри функции свертки. Его место занял необязательный аргумент с начальным значением. Если потребуется вызывать функцию свертки как метод конкретного объекта, можно воспользоваться методом Function.bind()
.
Следует отметить, что методы every()
и some()
, описанные выше, являются своеобразной разновидностью операции свертки массива. Однако они отличаются отreduce()
тем, что стремятся завершить обход массива как можно раньше и не всегда проверяют значения всех его элементов.
В примерах, представленных до сих пор, для простоты использовались числовые массивы, но методы reduce()
и reduceRight()
могут использоваться не только для математических вычислений. Взгляните на функцию union()
в примере 6.2. Она вычисляет «объединение» двух объектов и возвращает новый объект, имеющий свойства обоих. Эта функция принимает два объекта и возвращает другой объект, т. е. она действует как функция свертки, поэтому ее можно использовать с методом reduce()
и обобщить операцию создания объединения произвольного числа объектов:
var objects = [{х:1}, {у:2}, {z:3}];
var merged = objects.reduce(union); // => {x:1, y:2, z:3}
Напомню, что, когда два объекта имеют свойства с одинаковыми именами, функция union()
использует значение свойства второго аргумента, т.е. reduce()
и reduceRight()
могут давать разные результаты при использовании с функцией union():
var objects = [{х:1,а:1}, {у:2,а:2}, {z:3,а:3}]:
var leftunion = objects.reduce(union); // {x:1, y:2, z:3. a:3}
var rightunion = objects.reduceRight(union); // {x:1, y:2, z:3, a:1}