Array.prototype.reduceRight()

Метод reduceRight() застосовує функцію до акумулятора та кожного елемента масиву (справа наліво), зменшуючи його до єдиного значення.

Дивіться також Array.prototype.reduce(), який виконується зліва направо.

Синтаксис

arr.reduceRight(callback(accumulator, currentValue[, index[, array]])[, initialValue])

Параметри

callback
Функція, яка виконується на кожному елементі масиву. Приймає чотири аргументи:
accumulator
Значення, яке було повернене з попереднього виклику функції, або initialValue, якщо є. (Дивіться нижче.)
currentValue
Поточний елемент масиву, що опрацьовується.
indexOptional
Індекс поточного елемента масиву.
arrayOptional
Масив, для якого було викликано reduceRight().
initialValueOptional
Значення, що використовується в якості акумулятора для першого виклику callback. Якщо початкового значення нема, то буде використаний та пропущений останній елемент масиву. Виклик reduce або reduceRight на порожньому масиві без початкового значення створить виняток TypeError.

Значення, яке повертається

Значення, що є результатом зменшення.

Опис

Метод reduceRight виконує функцію зворотного виклику один раз для кожного елемента у масиві, крім порожніх елементів, отримуючи чотири аргументи: початкове значення (або значення від попереднього виклику функції), значення поточного елемента, поточний індекс та масив, обхід якого виконується.

Виклик функції callback у reduceRight виглядатиме десь так:

array.reduceRight(function(accumulator, currentValue, index, array) {
  // ...
});

Коли функція викликається вперше, accumulator та currentValue можуть мати одне з двох значень. Якщо значення initialValue було надане під час виклику reduceRight, тоді accumulator дорівнюватиме initialValue, а currentValue останньому елементу масиву. Якщо значення initialValue не визначено, тоді accumulator дорівнюватиме останньому елементу масиву, а currentValue передостанньому.

Якщо масив порожній, а initialValue не надано, то буде викинуто виняток TypeError. Якщо масив має лише один елемент (незалежно від позиції), і немає значення initialValue, або якщо initialValue надано, але масив порожній, це єдине значення повернеться без виклику callback.

Для прикладу, функція може виглядати так:

[0, 1, 2, 3, 4].reduceRight(function(accumulator, currentValue, index, array) {
  return accumulator + currentValue;
});

Функція зворотного виклику буде виконана чотири рази, аргументи та значення, які повертаються, наведені нижче:

callback accumulator currentValue index array вертає
перший виклик 4 3 3 [0, 1, 2, 3, 4] 7
другий виклик 7 2 2 [0, 1, 2, 3, 4] 9
третій виклик 9 1 1 [0, 1, 2, 3, 4] 10
четвертий виклик 10 0 0 [0, 1, 2, 3, 4] 10

Значення, яке повертає reduceRight буде тим, яке вертає останній виклик callback (10).

А якби ви надали значення initialValue, результат виглядав би так:

[0, 1, 2, 3, 4].reduceRight(function(accumulator, currentValue, index, array) {
  return accumulator + currentValue;
}, 10);
callback accumulator currentValue index array вертає
перший виклик 10 4 4 [0, 1, 2, 3, 4] 14
другий виклик 14 3 3 [0, 1, 2, 3, 4] 17
третій виклик 17 2 2 [0, 1, 2, 3, 4] 19
четвертий виклик 19 1 1 [0, 1, 2, 3, 4] 20
п'ятий виклик 20 0 0 [0, 1, 2, 3, 4] 20

Цього разу reduceRight, звісно, повернув би 20.

Приклади

Знайти суму елементів масиву

var sum = [0, 1, 2, 3].reduceRight(function(a, b) {
  return a + b;
});
// сума дорівнює 6

Вирівняти масив масивів

var flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
    return a.concat(b);
}, []);
// Результат [4, 5, 2, 3, 0, 1]

Виконати послідовно набір асинхронних функцій з функціями зворотного виклику, щоб кожна передавала свій результат у наступну

const waterfall = (...functions) => (callback, ...args) =>
  functions.reduceRight(
    (composition, fn) => (...results) => fn(composition, ...results),
    callback
  )(...args);

const randInt = max => Math.floor(Math.random() * max)

const add5 = (callback, x) => {
  setTimeout(callback, randInt(1000), x + 5);
};
const mult3 = (callback, x) => {
  setTimeout(callback, randInt(1000), x * 3);
};
const sub2 = (callback, x) => {
  setTimeout(callback, randInt(1000), x - 2);
};
const split = (callback, x) => {
  setTimeout(callback, randInt(1000), x, x);
};
const add = (callback, x, y) => {
  setTimeout(callback, randInt(1000), x + y);
};
const div4 = (callback, x) => {
  setTimeout(callback, randInt(1000), x / 4);
};

const computation = waterfall(add5, mult3, sub2, split, add, div4);
computation(console.log, 5) // -> 14

// те саме, що й:

const computation2 = (input, callback) => {
  const f6 = x=> div4(callback, x);
  const f5 = (x, y) => add(f6, x, y);
  const f4 = x => split(f5, x);
  const f3 = x => sub2(f4, x);
  const f2 = x => mult3(f3, x);
  add5(f2, input);
}

Різниця між reduce та reduceRight

var a = ['1', '2', '3', '4', '5']; 
var left  = a.reduce(function(prev, cur)      { return prev + cur; }); 
var right = a.reduceRight(function(prev, cur) { return prev + cur; }); 

console.log(left);  // "12345"
console.log(right); // "54321"

Визначення композиції функцій

Концепція композиції функцій проста - вона об'єднує функції. Це послідовний, справа наліво, виклик кожної функції з результатом попередньої.

/**
 * Композиція функцій - це підхід, в якому результат однієї функції
 * передається у іншу і т.д.
 *
 * h(x) = f(g(x))
 *
 * Виконання функцій відбувається справа наліво
 *
 * https://uk.wikipedia.org/wiki/Композиція_функцій
 */

const compose = (...args) => (value) => args.reduceRight((acc, fn) => fn(acc), value)

// Збільшує передане число на 1
const inc = (n) => n + 1

// Подвоює передане значення
const double = (n) => n * 2

// використання композиції функцій
console.log(compose(double, inc)(2)); // 6

// використання композиції функцій
console.log(compose(inc, double)(2)); // 5

Поліфіл

Метод reduceRight був доданий до стандарту ECMA-262 у 5-й версії; таким чином, він може не бути присутній у всіх реалізаціях стандарту. Ви можете обійти цю проблему, вставивши наступний код на початку ваших скриптів, це дозволить використовувати метод reduceRight у версіях, які не підтримують його початково.

// Функціональні кроки ECMA-262, версія 5, 15.4.4.22
// Довідка: http://es5.github.io/#x15.4.4.22
if ('function' !== typeof Array.prototype.reduceRight) {
  Array.prototype.reduceRight = function(callback /*, initialValue*/) {
    'use strict';
    if (null === this || 'undefined' === typeof this) {
      throw new TypeError('Array.prototype.reduce called on null or undefined');
    }
    if ('function' !== typeof callback) {
      throw new TypeError(callback + ' is not a function');
    }
    var t = Object(this), len = t.length >>> 0, k = len - 1, value;
    if (arguments.length >= 2) {
      value = arguments[1];
    } else {
      while (k >= 0 && !(k in t)) {
        k--;
      }
      if (k < 0) {
        throw new TypeError('Reduce of empty array with no initial value');
      }
      value = t[k--];
    }
    for (; k >= 0; k--) {
      if (k in t) {
        value = callback(value, t[k], k, t);
      }
    }
    return value;
  };
}

Специфікації

Специфікація Статус Коментар
ECMAScript 5.1 (ECMA-262)
The definition of 'Array.prototype.reduceRight' in that specification.
Standard Початкове визначення. Реалізоване у JavaScript 1.8.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Array.prototype.reduceRight' in that specification.
Standard
ECMAScript Latest Draft (ECMA-262)
The definition of 'Array.prototype.reduceRight' in that specification.
Draft

Сумісність з веб-переглядачами

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
reduceRightChrome Full support YesEdge Full support 12Firefox Full support 3IE Full support 9Opera Full support 10.5Safari Full support 4WebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yesnodejs Full support Yes

Legend

Full support  
Full support

Див. також