likes
comments
collection

JS数组常用方法之reduce

作者站长头像
站长
· 阅读数 14

reduce(回调,初始值?)

回调参数:累加器,当前值,当前索引,数组

1. 使用注意:

  1. 对数组中的每一项执行回调(若传入初始值,则第一项不执行回调,直接赋值给累加器)
  2. 若未传初始值,则第一个值不执行回调。首次累加器为数组第一项,当前值为第二项,当前索引为1。
  3. 若传入初始值,则首次累加器为数组第一项,当前值为第二项,当前索引为0
  4. 提供初始值通常更安全。
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
// reduce() 没有初始值
[ { x: 2 }, { x: 22 }, { x: 42 } ].reduce( maxCallback ); // NaN
[ { x: 2 }, { x: 22 }            ].reduce( maxCallback ); // 22
[ { x: 2 }                       ].reduce( maxCallback ); // { x: 2 }
[                                ].reduce( maxCallback ); // TypeError
var maxCallback2 = ( max, cur ) => Math.max( max, cur );
// map/reduce; 这是更好的方案,即使传入空数组或更大数组也可正常执行
[ { x: 22 }, { x: 42 } ].map( el => el.x )
                        .reduce( maxCallback2, -Infinity );

2. 案例:

(1)数组求和

[1, 2, 3].reduce((acc, cur) => acc + cur, 0)  // 无初始值时,传入初始值为0,结果为6
[1, 2, 3].reduce((acc, cur) => acc + cur, 1)  // 初始值为1时,结果为7

(2)对象数组的值求和

[ { x: 1 }, { x: 2 }, { x: 3 } ].reduce(() => acc + cur.x, 0)  // 6

(3)数组去重

// 数组元素类型为 string
let arr = ['a', 'b', 'a', 'c', 'b', 'c'];
let orderArr = arr.reduce((acc, cur) => {
	if(acc.indexOf(cur) === -1) {
  	acc.push(cur)
  }
  return acc
}, [])  // ['a', 'b', 'c']

// 数组元素类型为 string
let arr = [1, 2, 1, 3, 2, 1];
let orderArr = arr.sort().reduce((acc, cur) => {
	if(acc.length === 0 || acc[acc.length - 1] !== cur) {
  	acc.push(cur)
  }
  return acc
}, [])  // [1, 2, 3]

(4)数组扁平化(二维降为一维)

[[1, 2], [3, 4], [5, 6]].reduce((acc, cur) => acc.concat(cur), [])  // [1, 2, 3, 4, 5, 6]

延展:flat方法:指定深度遍历数组(默认为1,可不传),并返回合并后的新数组。

[1, 2, [3, 4]].flat();    // [1, 2, 3, 4]
[1, 2, [[[3, 4]]]].flat(2); // [1, 2, [3, 4]]

(5)数组元素计数

var num = ['a', 'b', 'a'].reduce((acc, cur) => {
	if(cur in acc) {
  	acc[cur]++;
  } else {
  	acc[cur] = 1;
  }
  return acc;
}, {}) // {a: 2, b: 1}

(6)属性分类

const people = [{name: 'zs', age: 18},      		{name: 'ls', age: 18},      		{name: 'ww', age: 20}];
const getGroup = (prop) => people.reduce((acc, cur) => {
   let val = cur[prop];
   if(!acc[val]) {
      acc[val] = []
   }
   acc[val].push(cur);
   return acc;
}, {});
console.log(getGroup('age'))

{
    20: [{name: 'zs', age: 18}, {name: 'ls', age: 18}],
    21: [{name: 'ww', age: 20}]
}

(7)提取和合并对象数组中的数组

const people = [{        name: 'zs',        age: 18,        hobbies: ['singing', 'dancing']
      },
      {
        name: 'ls',
        age: 18,
        hobbies: ['reading']
      },
      {
        name: 'ww',
        age: 20,
        hobbies: ['running', 'playing basketball']
      }
    ];
const allHobbies = people.reduce((acc, cur) => [...acc, ...cur.hobbies], ['travelling']);
// allHobbies: ['travelling', 'singing', 'dancing', 'reading', 'running', 'playing basketball']

(8)数组转换为对象

// 使用 reduce
const people = [{name: 'zs', age: 18},
                {name: 'ls', age: 18},
                {name: 'ww', age: 20}];
const newObj = people.reduce((acc, cur) => {
      acc[cur.name] = cur.age;
      return acc
    }, {});
// reduce中的回调可以简化:
// const newObj = people.reduce((acc, cur) => (acc[cur.name] = cur.age, acc), {});
// 该形式利用了逗号操作符:对括号里的每一项求值,返回最后一项
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Comma_Operator

console.log(newObj)
// {zs: 18, ls: 18, ww: 20}
// 使用 Object.fromEntries
const people = [{name: 'zs', age: 18},
                {name: 'ls', age: 18},
                {name: 'ww', age: 20}];
const newObj = Object.fromEntries(
      people.map(({name, age}) => [name, age])
    )
console.log(newObj)

// {zs: 18, ls: 18, ww: 20}

(9)按顺序运行Promise

const f1 = val => new Promise((res, ret) => res(val * 10))
const f2 = val => new Promise((res, ret) => res(val * 20))
const f3 = val => new Promise((res, ret) => res(val * 30))
const promiseArr = [f1, f2, f3]
promiseArr.reduce((acc, cur) => acc.then(cur), Promise.resolve(5)).then(console.log)
// 30000

(10)功能型函数管道

const double = x => x * 2
const triple = x => x * 3
const quadruple = x => x * 4
    
const pipe = (...functions) => initVal => functions.reduce((acc, cur) => cur(acc), initVal)

const mul_6 = pipe(double, triple)
const mul_12 = pipe(triple, quadruple)

console.log(mul_6(1))  // 6
console.log(mul_6(2))  // 12
console.log(mul_12(1))  // 12
console.log(mul_12(2))  // 24

参考文献:

1.developer.mozilla.org/z/docs/Web/… 2.segmentfault.com/q/101000004…