reduce的一些个人用法

263 阅读4分钟

对于习惯函数式编程的人来说ES6提供的reduce这个数组api宛如天籁。总结一些reduce的个人用法。

一. 常规用法

1.字符串
2.数组
3.对象

返回字符串 如 const arr = ['hello', 'world'...],拼接字符串(数字相加同理)

const res = ['hello', 'world'].reduce((r, c) => {
  return `${r}${c} `
}, '')
    

res => hello world 

返回数组 如 const arr = ['hello', 'world'...],数组每个元素字符串末尾加上‘s’

const res = ['hello', 'world'].reduce((r, c) => {
    return [
        ...r,
        `${c}s`
    ]
}, [])

res => ['hellos', 'worlds']

返回对象 如 const arr = [{id, '1', name: 'tom'}, {id: '2', name: 'jerry'}] 对象数组中的元素拥有唯一的id值,将数组改造为对象

const res = [{id, '1', name: 'tom'}, {id: '2', name: 'jerry'}].reduce((r, c) => {
    return {
        ...r,
        [c.id]: c
    }
}, {})

res => {
    1: {
        id: '1',
        name: 'tom'
    },
    2: {
        id: '2',
        name: 'jerry'
    }
}

看到这儿是不是有点感觉了。reduce这个api接收两个参数,第一个参数回调函数针对遍历操作,第二个参数定义return累加器的初始值以及数据类型,如同map、forEach在外部定义变量temp,遍历过程中对该对象temp进行操作。

如下图所示reduce第一个回调函数参数介绍的三个参数,r是个累加器每次遍历都会对r进行操作,最终return的就是该值,由于该示例代码没有return的原因所以只打印了初始值的[]后,每次遍历return出来的都是undefined。

所以对r进行操作显得就是该api的精髓所在,下面结合一道去重的题目来看这个api的使用方法.

数组 [1, 2, 1, 2, null, null, undefined, undefined] 去重

整理思路:对象的key值一样会自动覆盖以达到去重的效果,那么是不是意味
着reduce可以针对数组做一次数据类型转换达到去重的目的?

const res = [1, 2, 1, 2, null, null, undefined, undefined].reduce((r, c, i) => {
    // 针对r做数据操作,没进遍历之前r是个空对象
    r[c] = c
    return r
}, {})//这里默认值和类型给为对象

运行js输出的res是一个去重过后的对象

{ '1': 1, '2': 2, null: null, undefined: undefined }

数组被完美的转换为了对象,Object.values(res) 就完成了去重。

那么使用es6的解构赋值来进行操作r会不会显得更优雅?

r 是个对象,且新构建的item不停地往里累加

return {
    ...r, //上一次累加的r
    [c]: c //当前遍历的元素
} //替代上述的
    ...
    r[c] = c
    return r
    ...

一些实际开发中的例子。
1.列表查询的性能优化,组装数据结构
2.指定某些挑选某些数据中的某些数据
...

1.列表查询的性能优化,组装数据结构:
    不管是使用什么前端框架总是避免不了一些代码层面的优化,比如前端查询列表中的某一条数据
    如果数据量较大且不停的利用遍历去找匹配的id会浪费不必要的性能,故对数据进行数据结构转
    换显然更为合适。
    
    如上述的返回对象的例子所示,将列表的唯一id作为key,数组转对象,存储该对象
    每次获取元素只需要obj.[id]即可,避免了不必要的遍历操作

2.指定某些挑选某些数据中的某些数据:
    开发中可能后端返回了一大堆数据,但是前端相应视图是需要一部分数据,那么用reduce重构数据
    结构是个不错的选择!
const data = [
  {
    id: '1',
    name: "tom",
    age: 20
  },
  {
    id: '2',
    name: "tom2",
    age: 21
  },
  {
    id: '3',
    name: "tom3",
    age: 22
  },
]

现在需要去获取所有的age字段 组成一个新的数组

const res = data.reduce((r, c, i) => {
    r.push(c.age)
    return r
}, [])

同样也可使用解构的方法
const res = data.reduce((r, c, i) => {
    return [
        ...r,
        c.age
    ]
}, [])

res => [20, 21, 22]

二. 异步请求嵌套

在一中提到了reduce的两个参数,第二个参数定义类型和初始值,那么promise它支持吗?没想到 还真支持😂,那么意味着在reduce中进行数据操作的同时可以进行异步请求,并且将请求结果重新塞入到预备return的新数据解构中,这可太骚了!

const obj = await result.reduce(async (p, c) => {
    return p.then(async (r) => {
        const { data } = await request(c.xxxUrl)
        return {
            ...r,
            [c.id]: {
                ...c,
                list: data.xxx
            }
        }
    })
}, Promise.resolve({}))

实际上传入的p就是个promise的resolve状态的对象,故在解p的时候可以直接拿回async await
的返回值