Skip to content

reduce() ​

本节目标:理解“reduce()”的核心思路,并能把它用于实际开发或面试表达。 reduce为数组中的每一个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素,callback函数接受四个参数:

  • accumulator [ə'kjuːmjʊleɪtə]美 [ə'kjumjəletɚ] 累计器
  • currentValue 当前值
  • currentIndex 当前索引
  • array ==数组==

回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:

  • 如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;
  • 如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。

注意:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。

如果数组为空且没有提供initialValue,会抛出

TypeError

。 如果数组仅有一个元素(无论位置如何)并且没有提供initialValue; 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。

提供初始值通常更安全,正如下面的例子,如果没有提供initialValue,则可能有三种输出:

var maxCallback = ( pre, cur ) => Math.max( pre.x, cur.x );var maxCallback2 = ( max, cur ) => Math.max( max, cur );
// reduce() without initialValue

没有初始值

[ { x: 22 }, { x: 42 } ].reduce( maxCallback ); // 42[ { x: 22 }            ].reduce( maxCallback ); // { x: 22 }[                      ].reduce( maxCallback ); // TypeError
// map/reduce; better solution, also works for empty arrays[ { x: 22 }, { x: 42 } ].map( el => el.x )                        .reduce( maxCallback2, -Infinity );
reduce

如何运行 假如运行下段代码:

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

==被调用四次,每次调用的参数和返回值如下表:==

次acccurIndexarrayval
1011[0, 1, 2, 3, 4]1
2122[0, 1, 2, 3, 4]3
3333[0, 1, 2, 3, 4]6
4644[0, 1, 2, 3, 4]10

由reduce返回的值将是上次回调调用的值(10)。 你同样可以使用箭头函数的形式,下面的代码会输出跟前面一样的结果 您还可以提供

Arrow Function

代替完整功能。 下面的代码将产生与上面的代码中相同的输出: [0, 1, 2, 3, 4].reduce((prev, curr) =\> prev + curr ); 如果你打算提供一个初始值作为reduce方法的第二个参数,以下是运行过程及结果: [0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) =\> { return accumulator + currentValue; }, 10 );

callbackaccumulatorcurrentValuecurrentIndexarrayreturn value
first call1000[0, 1, 2, 3, 4]10
second call1011[0, 1, 2, 3, 4]11
third call1122[0, 1, 2, 3, 4]13
fourth call1333[0, 1, 2, 3, 4]16
fifth call1644[0, 1, 2, 3, 4]20

这种情况下reduce返回的值是20。 例子数组里所有值的和

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

你也可以写成箭头函数的形式:

var total = [ 0, 1, 2, 3 ].reduce(  ( acc, cur ) => acc + cur,

0);

累加对象数组里的值 要累加对象数组中包含的值,必须提供初始值,以便各个item正确通过你的函数。

var initialValue = 0;var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {    return accumulator + currentValue.x;},initialValue)
console.log(sum) // logs 6

你也可以写成箭头函数的形式:

var initialValue = 0;var sum = [{x: 1}, {x:2}, {x:3}].reduce(    (accumulator, currentValue) => accumulator + currentValue.x    ,initialValue);
console.log(sum) // logs 6

将二维数组转化为一维

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(  function(a, b) {    return a.concat(b);  }, []);// flattened is [0, 1, 2, 3, 4, 5]

你也可以写成箭头函数的形式:

var flattened = [[0, 1], [2, 3], [4, 5]].reduce( ( acc, cur ) => acc.concat(cur), []);

计算数组中每个元素出现的次数

var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
var countedNames = names.reduce(function (allNames, name) {   if (name in allNames) {    allNames[name]++;  }  else {    allNames[name] = 1;  }  return allNames;}, {});// countedNames is:// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

按属性对object分类

var people = [  { name: 'Alice', age: 21 },  { name: 'Max', age: 20 },  { name: 'Jane', age: 20 }];
function groupBy(objectArray, property) {  return objectArray.reduce(function (acc, obj) {    var key = obj[property];    if (!acc[key]) {      acc[key] = [];    }    acc[key].push(obj);    return acc;  }, {});}
var groupedPeople = groupBy(people, 'age');// groupedPeople is:// { //   20: [//     { name: 'Max', age: 20 }, //     { name: 'Jane', age: 20 }//   ], //   21: [{ name: 'Alice', age: 21 }] // }

使用扩展运算符和initialValue绑定包含在对象数组中的数组// friends - 对象数组

// where object field "books" - list of favorite books var friends = [{  name: 'Anna',  books: ['Bible', 'Harry Potter'],  age: 21}, {  name: 'Bob',  books: ['War and peace', 'Romeo and Juliet'],  age: 26}, {  name: 'Alice',  books: ['The Lord of the Rings', 'The Shining'],  age: 18}];
// allbooks - list which will contain all friends' books +  // additional list contained in initialValuevar allbooks = friends.reduce(function(prev, curr) {  return [...prev, ...curr.books];}, ['Alphabet']);
// allbooks = [//   'Alphabet', 'Bible', 'Harry Potter', 'War and peace', //   'Romeo and Juliet', 'The Lord of the Rings',//   'The Shining'// ]

数组去重

let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];let result = arr.sort().reduce((init, current)=>{    if(init.length===0 || init[init.length-1]!==current){        init.push(current);    }    return init;}, []);console.log(result); //[1,2,3,4,5]
/** * Runs promises from array of functions that can return promises * in chained manner * * @param {array} arr - promise arr * @return {Object} promise object */function runPromiseInSequence(arr, input) {  return arr.reduce(    (promiseChain, currentFunction) => promiseChain.then(currentFunction),    Promise.resolve(input)  );}
// promise function 1function p1(a) {  return new Promise((resolve, reject) => {    resolve(a * 5);  });}
// promise function 2function p2(a) {  return new Promise((resolve, reject) => {    resolve(a * 2);  });}
// function 3  - will be wrapped in a resolved promise by .then()function f3(a) { return a * 3;}
// promise function 4function p4(a) {  return new Promise((resolve, reject) => {    resolve(a * 4);  });}
const promiseArr = [p1, p2, f3, p4];runPromiseInSequence(promiseArr, 10)  .then(console.log);   // 1200

==功能型函数管道==

Section
// Building-blocks to use for compositionconst double = x => x + x;const triple = x => 3 * x;const quadruple = x => 4 * x;
// Function composition enabling pipe functionalityconst pipe = (...functions) => input => functions.reduce(    (acc, fn) => fn(acc),    input);
// Composed functions for multiplication of specific valuesconst multiply6 = pipe(double, triple);const multiply9 = pipe(triple, triple);const multiply16 = pipe(quadruple, quadruple);const multiply24 = pipe(double, triple, quadruple);
// Usagemultiply6(6); // 36multiply9(9); // 81multiply16(16); // 256multiply24(10); // 240
PolyfillSection
// Production steps of ECMA-262, Edition 5, 15.4.4.21// Reference: http://es5.github.io/#x15.4.4.21// https://tc39.github.io/ecma262/#sec-array.prototype.reduceif (!Array.prototype.reduce) {  Object.defineProperty(Array.prototype, 'reduce', {    value: function(callback /*, initialValue*/) {      if (this === null) {        throw new TypeError( 'Array.prototype.reduce ' +           'called on null or undefined' );      }      if (typeof callback !== 'function') {        throw new TypeError( callback +          ' is not a function');      }
// 1. Let O be ? ToObject(this value).      var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).      var len = o.length >>> 0;
// Steps 3, 4, 5, 6, 7            var k = 0;       var value;
if (arguments.length >= 2) {        value = arguments[1];      } else {        while (k < len && !(k in o)) {          k++;         }
// 3. If len is 0 and initialValue is not present,        //    throw a TypeError exception.        if (k >= len) {          throw new TypeError( 'Reduce of empty array ' +            'with no initial value' );        }        value = o[k++];      }
// 8. Repeat, while k < len      while (k < len) {        // a. Let Pk be ! ToString(k).        // b. Let kPresent be ? HasProperty(O, Pk).        // c. If kPresent is true, then        //    i.  Let kValue be ? Get(O, Pk).        //    ii. Let accumulator be ? Call(        //          callbackfn, undefined,        //

« accumulator, kValue, k, O »

).        if (k in o) {          value = callback(value, o[k], k, o);        }
// d. Increase k by 1.              k++;      }
// 9. Return accumulator.      return value;    }  });}

==如果您需要兼容不支持==

Object.defineProperty

==的==JavaScript==引擎,那么最好不要== polyfill Array.prototype==方法,因为你无法使其成为不可枚举的。==

本站总访问 — 次