Array.prototype.reduceRight() - JavaScript 编辑

reduceRight() 方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。

对于从左至右遍历的相似方法请参阅 Array.prototype.reduce().

语法

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

参数

callback
一个回调函数,用于操作数组中的每个元素,它可接受四个参数:
accumulator
累加器:上一次调用回调函数时,回调函数返回的值。首次调用回调函数时,如果 initialValue 存在,累加器即为 initialValue,否则须为数组中的最后一个元素(详见下方 initialValue 处相关说明)。
currentValue
当前元素:当前被处理的元素。
index可选
数组中当前被处理的元素的索引。
array可选
调用 reduceRight() 的数组。
initialValue可选 
首次调用 callback 函数时,累加器 accumulator 的值。如果未提供该初始值,则将使用数组中的最后一个元素,并跳过该元素。如果不给出初始值,则需保证数组不为空。
否则,在空数组上调用 reducereduceRight 且未提供初始值(例如 [].reduce( (acc, cur, idx, arr) => {} ) )的话,会导致类型错误 TypeError: reduce of empty array with no initial value

返回值

执行之后的返回值。

描述

reduceRight 为数组中每个元素调用一次 callback 回调函数,但是数组中被删除的索引或从未被赋值的索引会跳过。回调函数接受四个参数:初始值(或上次调用回调的返回值)、当前元素值、当前索引,以及调用迭代的当前数组。

可以像下面这样调用 reduceRight 的回调函数 callback

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

首次调用回调函数时,accumulatorcurrentValue 的可能取值情况有两种:

  • 如果在调用 reduceRight 时提供了 initialValue 参数,则 accumulator 等于 initialValuecurrentValue 等于数组中的最后一个元素。
  • 如果没有提供 initialValue 参数,则 accumulator 等于数组最后一个元素, currentValue 等于数组中倒数第二个元素。

如果数组为空,但提供了 initialValue 参数,或如果数组中只有一个元素,且没有提供 initialValue 参数,将会直接返回 initialValue 参数或数组中的那一个元素。这两种情况下,都不会调用 callback 函数。

如果数组为空,且没有提供 initialValue 参数,则会抛出一个 TypeError 错误。

最终,首次调用时的情况可汇总为此表:

数组内元素数量是否提供 initialValue结果
> 1未提供accumulator数组中(下略)最后一个元素
currentValue 为倒数第二个元素
提供accumulator 为 initialValue
currentValue 为最后一个元素
= 1未提供直接返回数组中的唯一一个元素
= 0提供直接返回 initialValue
未提供抛出 TypeError 错误

该函数的完整执行过程见下例:

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

一共会调用四次回调函数,每次调用的参数及返回值如下:

callbackpreviousValuecurrentValueindexarray返回值
第一次调用433[0,1,2,3,4]7
第二次调用722[0,1,2,3,4]9
第三次调用911[0,1,2,3,4]10
第四次调用1000[0,1,2,3,4]10

reduceRight 返回值是最后一次调用回调的返回值(10)。

如果提供了一个 initialValue 参数,则结果如下:

[0, 1, 2, 3, 4].reduceRight(function(previousValue, currentValue, index, array) {
    return previousValue + currentValue;
}, 10);
callbackpreviousValuecurrentValueindexarray返回值
第一次调用1044[0,1,2,3,4]14
第二次调用1433[0,1,2,3,4]17
第三次调用1722[0,1,2,3,4]19
第四次调用1911[0,1,2,3,4]20
第五次调用2000[0,1,2,3,4]20

这时,reduceRight 返回值为 20。

示例

求一个数组中所有值的和

var sum = [0, 1, 2, 3].reduceRight(function(a, b) {
  return a + b;
});
// sum is 6

扁平化(flatten)一个二维数组

var flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
    return a.concat(b);
}, []);
// flattened is [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

// same as:

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"

定义可组合函数

组合函数的概念简单,它只是简单地结合了多个函数。它是一个从右向左流动的函数,用上一个函数的输出调用每个函数。

/**
 * Function Composition is way in which result of one function can
 * be passed to another and so on.
 *
 * h(x) = f(g(x))
 *
 * Function execution happens right to left
 *
 * https://en.wikipedia.org/wiki/Function_composition
 */

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

// Increament passed number
const inc = (n) => n + 1

// Doubles the passed value
const double = (n) => n * 2

// using composition function
console.log(compose(double, inc)(2)); // 6

// using composition function
console.log(compose(inc, double)(2)); // 5

兼容旧环境(Polyfill)

reduceRight 被添加到 ECMA-262 标准第 5 版,因此它在某些实现环境中可能不被支持。把下面的代码添加到脚本开头可以解决此问题,从而允许在那些没有原生支持 reduceRight 的实现环境中使用它。

// Production steps of ECMA-262, Edition 5, 15.4.4.22
// Reference: 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.reduceRight 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('reduceRight 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;
  };
}

规范

SpecificationStatusComment
ECMAScript 5.1 (ECMA-262)
Array.prototype.reduceRight
StandardInitial definition.
Implemented in JavaScript 1.8
ECMAScript 2015 (6th Edition, ECMA-262)
Array.prototype.reduceRight
Standard
ECMAScript (ECMA-262)
Array.prototype.reduceRight
Living Standard

浏览器兼容性

BCD tables only load in the browser

The compatibility table in this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.

相关链接

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

词条统计

浏览:134 次

字数:15846

最后编辑:7年前

编辑次数:0 次

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文