javascript函数式编程06-高阶函数(Array.reduce())

543 阅读4分钟

这是我参与更文挑战的第6天,活动详情查看: 更文挑战

紧跟上一篇 ,这一篇主要了解高阶函数(Array.reduce())

什么是reduce?
  • reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

  • reduce() 可以作为一个高阶函数,用于函数的 compose。

  • 语法

    array.reduce(function(prev, cur, index, arr), init)

    • prev (上一次调用回调返回的值,或者是提供的初始值(initialValue))

    • cur (数组中当前被处理的元素)

    • index (当前元素在数组中的索引)

    • arr (调用的数组)

    • init (传递给函数的初始值)

    • 若传入初始值,accumulator首次迭代就是初始值,否则就是数组的第一个元素;后续迭代中将是上一次迭代函数返回的结果。所以,假如数组的长度为n,如果传入初始值,迭代次数为n;否则为n-1。

    • 比如实现数组 arr = [1,2,3,4] 求数组的和

let arr = [1,2,3,4];
arr.reduce(function(pre,cur){return pre + cur}); // return 10
  • 浏览器支持情况

640.webp

reduce的常见的几种的用法
  • reduce累加
//带初始值
var arr = [1,2,3,4]
var sum = arr.reduce((pre, item) => {
    return pre + item
}, 10)
console.log(sum) // 20

//不带初始值
var arr = [1,2,3,4]
var sum = arr.reduce((pre, item) => {
    return pre + item
},)
console.log(sum) // 10
  • reduce数组去重
var arr = [1,2,3,3,2,1,4]
arr.reduce((acc, cur) => {
  if (!(acc.includes(cur))) {
    acc.push(cur)
  }
  return acc
}, [])
// [1, 2, 3, 4]
  • reduce求数组项最大值
var arr = [1, 2, 3, 4];
arr.reduce((prev, cur) => {
    return Math.max(prev,cur);
});
//4
  • reduce将二维数组转为一维数组
var arr = [[1,2], [3,4], [5,6]]
arr.reduce((acc, cur) => {
  return acc.concat(cur)
}, [])
// [1,2,3,4,5,6]
  • reduce对象里的属性求和
var arr = [
    {subject: 'Math', score: 90},
    {subject: 'Chinese', score: 90},
    {subject: 'English', score: 100}
]
arr.reduce((pre, cur) => {
    return cur.score + pre
}, 0)
//280
  • reduce计算数组中每个元素出现的个数
var arr = [1, 2,3,3,2,1,2,1]
arr.reduce((acc, cur) => {
  if (!(cur in acc)) {
    acc[cur] = 1
  } else {
    acc[cur] += 1
  }
  return acc
}, {})
//{1: 3, 2: 3, 3: 2}
  • reduce按属性给数组分类
var arr = [
    {subject: 'Math', score: 90},
    {subject: 'Chinese', score: 90},
    {subject: 'English', score: 100},
    {subject: 'Math', score: 80},
    {subject: 'Chinese', score: 95}
];
arr.reduce((acc, cur) => {
  if (!acc[cur.type]) {
    acc[cur.type] = [];
  }
  acc[cur.type].push(cur)
  return acc
}, {})
  • reduce实现map
var arr = [1, 2, 3, 4]
Array.prototype.reduceMap = function(callback) {
  return this.reduce((acc, cur, index, array) => {
    const item = callback(cur, index, array)
    acc.push(item)
    return acc
  }, [])
}
arr.reduceMap((item, index) => {
  return item + index
})
// [1, 3, 5, 7]

  • reduce实现forEach
var arr = [1, 2, 3, 4]
Array.prototype.reduceForEach = function(callback) {
  this.reduce((acc, cur, index, array) => {
    callback(cur, index, array)
  }, [])
}

arr.reduceForEach((item, index, array) => {
  console.log(item, index)
})
// 1234
// 0123
  • reduce实现filter
var arr = [1, 2, 3, 4]
Array.prototype.reduceFilter = function (callback) {
   return this.reduce((acc, cur, index, array) => {
    if (callback(cur, index, array)) {
      acc.push(cur)
    }
    return acc
  }, [])
}
arr.reduceFilter(item => item % 2 == 0) // 过滤出偶数项。
// [2, 4]
  • reduce实现find
var arr = [1, 2, 3, 4]
var obj = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }]
Array.prototype.reduceFind = function (callback) {
  return this.reduce((acc, cur, index, array) => {
    if (callback(cur, index, array)) {
      if (acc instanceof Array && acc.length == 0) {
        acc = cur
      }
    }    
    if ((index == array.length - 1) && acc instanceof Array && acc.length == 0) {
      acc = undefined
    }
    return acc
  }, [])
}
arr.reduceFind(item => item % 2 == 0) // 2
obj.reduceFind(item => item.a % 2 == 0) // {a: 2}
obj.reduceFind(item => item.a % 9 == 0) // undefined
reduce的重要的用法
  • 将数组转换为对象
  • 在实际业务开发中,你可能遇到过这样的情况,后台接口返回的数组类型,你需要将它转化为一个根据id值作为key,将数组每项作为value的对象进行查找。 例如:
const peopleArr = [
  {
    id: 1,
    username: 'limei',
    sex: 0,
    email: 'limei@163.com'
  },
  {
    id: 2,
    username: 'ajerry',
    sex: 1,
    email: 'jerrydfsd@qq.com'
  },
  {
    id: 3,
    username: 'jnancy',
    sex: 0,
    email: ''
  }
];

function keyByUserReducer(acc, person) {
    return {...acc, [person.id]: person};
}
const userObj = peopleArr.reduce(keyByUserReducer, {});
console.log(userObj);
  • 按顺序运行异步函数
  • 我们可以做的另一件事.reduce()是按顺序运行promises(而不是并行)。如果您对API请求有速率限制,或者您需要将每个prmise的结果传递到下一个promise,reduce可以帮助到你
function fetchMessages(username) {
 return fetch(`https://example.com/api/messages/${username}`)
  .then(response => response.json());
}

function getUsername(person) {
 return person.username;
}

async function chainedFetchMessages(p, username) {
 // In this function, p is a promise. We wait for it to finish,
 // then run fetchMessages().
 const obj = await p;
 const data = await fetchMessages(username);
 return { ...obj, [username]: data};
}

const msgObj = userList
 .map(getUsername)
 .reduce(chainedFetchMessages, Promise.resolve({}))
 .then(console.log);
// {glestrade: [ … ], mholmes: [ … ], iadler: [ … ]}
  • async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

  • 请注意,在此我们传递Promise作为初始值Promise.resolve(),我们的第一个API调用将立即运行。

  • koa的源码中,有一个only模块,整个模块就一个简单的返回reduce方法操作的对象:

var only = function(obj, keys){
 obj = obj || {};
 if ('string' == typeof keys) keys = keys.split(/ +/);
 return keys.reduce(function(ret, key){
  if (null == obj[key]) return ret;
  ret[key] = obj[key];
  return ret;
 }, {});
};
  • 通过对reduce概念的理解,这个模块主要是想新建并返回一个obj对象中存在的keys的object对象。
var a = {
  env : 'development',
  proxy : false,
  subdomainOffset : 2
}
only(a,['env','proxy'])  // {env:'development',proxy : false}
  • 以上所述是给大家介绍的详解JS数组Reduce()方法详解及高级技巧,希望对大家有所帮助