js数组reduce在项目中的实用

JavaScript中循环数组除了有for循环forEachmapfiltereverysome等外还有一个非常好用的reduce

reduce会循环数组中的每一项,在循环过程中我们可以对根据需要对任意一项进行处理,并返回处理后的数据,循环结束后reduce会将之前返回的数据进行汇总,最终我们只得到一个结果。有点类似于map方法,但map只能返回一个数组,而reduce可以返回任意类型的数据

reduce用法:

// 没有初始值
let res = arr.reduce((res, item, index, arr) => {
    ...
});

/* 传递一个初始值。传递的初始值的数据类型是什么,reduce最后得到的结果的数据类型就是什么
    此处 res2 变量的结果是一个对象
*/
let res2 = arr.reduce((res, item, index, arr) => {
    ...
}, {});

1、计算数组中所有数字的和

let arr = [10,55.9,21,0.1,3,8];

let res = arr.reduce((res, item) => {
  // 由于没有给初始值,第一次循环的时候 res 为undefined
  let sum = (typeof res === 'undefined') ? (0 + item) : res + item;
  // 这里一定要将结果return出去,否则后面的循环中res就为undefined了
  return sum;
});
console.log('res', res); // 输出结果为:98

2、计算总分数

这题与第1题基本上是相似的,但在实际工作中这题的情况比较多

let arr = [
  {subject: '语文', score: 90},
  {subject: '数学', score: 80},
  {subject: '英语', score: 78}
];
// 这里一定要给个初始值,否则res为当前循环项
let res = arr.reduce((res, item) => {
  let score = item.score;
  let sum = res + score;
  
  return sum;
}, 0);
console.log(res); // 248

3、统计数组中重复字母出现的次数

let arr = ['a','e','b','a','c','d','d','e'];
let res = arr.reduce((res, item) => {
  // 由于传递了初始值,所以第1次循环的时候res就是一个object,不会为undefined
  if(item in res){
    res[item] = res[item] + 1;
  }else{
    res[item] = 1;
  }
  /*
    {
      a: 2,
      e: 2,
      b: 1,
      c: 1,
      d: 2
    }
  */
  return res;
}, {});
console.log(res);

4、多个异步变同步执行(2020-06-19)

在ES6时代我们可以很方便的使用promise,在不使用Promise.all的情况下如何使多个promise同步执行呢?
比如我们有3个接口,A、B、C,它们的依赖关系是C->B->A,在不使用Promise.all的情况下如何才能达到Promise.all的效果?
请看下面代码

// 获取产品列表
function getProductList() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('getProductList');
      let productList = [
        {id: '1', name: '华为P30'},
        {id: '2', name: '华为P30 Pro'}
      ];
      resolve(productList[0].id);
    }, 1000);
  });
}
// 根据产品id获取产品详情
function getProductInfo(pid) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('getProductInfo', pid);
      let product = {
        id: '1',
        name: '华为P30',
        price: 3500,
        cid: 'c_1'
      };
      resolve(product.cid);
    }, 700);
  });
}
// 获取产品的父分类
function getProductParentCategory(cid) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('getProductParentCategory', cid);
      resolve({
        id: 'c_1',
        cname: '高端手机'
      });
    }, 300);
  });
}

/**
 * 组合promise
 * @param promises
 * @returns {function(...[*]=)}
 */
function composePromise(...promises) {
  let res = function() {
    return promises.reduce((res, item) => {
      return res.then(item);
    }, Promise.resolve());
  }
  return res();
}

composePromise(getProductList, getProductInfo, getProductParentCategory)
  .then(res => {
    console.log('三个promise执行结束了');
    console.log('父分类',res);
  })
  .catch(err => {
    console.error(err);
  });
阅读 125

推荐阅读