比你想象中更强大的 reduce 以及对敲码的思考

前言
前面的这篇文章 JS 基础\! | 扁平数组和JSON树的转换[2] 利用到了 reduce来实现数组转为map,以及结合concat实现数组递归拼接。今天我们来看看还能搞些什么名堂~

简单复习一下 reduce
语法
let value = arr.reduce(function(previousValue, item, index, array) {
  // ...
}, [initial]);

参数:
previousValue: 上一个函数调用的结果,第一次等于 initial(如果提供了 initial 的话)。
item : 当前的数组元素。
index :当前索引。
arr : 数组本身。
previousValue实际上有点像累加,所以一些地方也会叫将这个参数称为accumulator ,存储前面所有的执行结果,最后会成为reduce的结果。

可读性
但通常,你一般是不会完全参照这些参数定义的意思来决定参数名称,而是要看具体开发遇到的场景来给其取可读性高的名称。

部分应用
1. 经典累加器
将数组中的值从左到右累加,大家学reduce的时候第一个例子应该就是这个。这里只是简单的提一下,不是本文的重点~

const a = [1, 2, 8, 7, 4];

const sum = a.reduce((pre, cur) => {
 const res = pre + cur;
 return res;
}, 0);

console.log(sum); // 22

2. 二维数组转一维
结合 concat 实现数组扁平化

const arr2 = [
 [1, 2],
 [3, 4],
 [5, 6],
].reduce((acc, cur) => {
 return acc.concat(cur);
}, []);

console.log(arr2); //

3. 多维数组扁平
这个算是上一个的进阶和更为通用的版本~
这篇文章[3]里就用到了类似的,结合 concat 和递归

const arr3 = [
 [1, 2],
 [3, 4],
 [5, [7, [9, 10], 8], 6],
];
const flatten = arr =>
 arr.reduce(
  (pre, cur) => pre.concat(Array.isArray(cur) ? flatten(cur) : cur),
  []
 );
console.log(flatten(arr3)); // [ 1, 2, 3, 4, 5, 7, 9, 10, 8, 6 ]






4. 数组分块
根据传入限制大小,对数组进行分块。
小于限制长度时就往里添加,否则直接将其加入res

const chunk = (arr, size) => {
 return arr.reduce(
  (res, cur) => (
   res[res.length - 1].length < size
    ? res[res.length - 1].push(cur)
    : res.push([cur]),
   res
  ),
  [[]]
 );
};
const arr4 = [1, 2, 3, 4, 5, 6];
console.log(chunk(arr4, 3)); // [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]

5. 字符统计
统计文本中各个字的数量

const countChar = text => {
 text = text.split("");
 return text.reduce((record, c) => {
  record[c] = (record[c] || 0) + 1;
  return record;
 }, {});
};
const text = "划水水摸鱼鱼";
console.log(countChar(text)); // { '划': 1, '水': 2, '摸': 1, '鱼': 2 }

思考
本文只讲了几个应用,其实还有更多的应用,以及一些实现 JS API 的功能,比如

数组填充
求最大、最小值
reverse
map
...
等等,这些代码段的整合网上已经有够多了,我这里想总结一下写出这些实用、通用的代码需要进行怎样的思考

core-js
其实从 Polyfill ofArray.prototype.reduceincore-js[4] 中可以从另一个角度理解 reduce 中第一个参数回调函数中接收的第一个参数:

class Array {
  //...
  reduce(callbackfn: (memo: any, value: any, index: number, target: any) => any, initialValue?: any): any;
 //...
}

他这里用的是 memo,中文直接翻译过来就是备忘录,在计算机中我们或许更为喜欢用缓存。我个人认为是更为符合我们写出好用的代码片段的。
他的精髓所在正是将回调函数作用于数组中的各个成员上,而上一次return的值就作为memo,传入到下一个之中,你可以在这里面逐一处理:

不断更新迭代(累加)
将结果拼接(扁平化)
将特定的值添加到同一个对象之中(字符统计)
最后作为想要得到最终效果展现出来~

总结



写代码,大概是这么几个节点

了解语法
传参
返回
真正领悟到语言的特性,并能将其运用到实际开发中,写出更好更简洁更实用的代码
多看:要从从这些代码段中以及网上各路好汉写的实用代码学习怎么样真正地像写诗一样写代码~
多写
第四步的多看,我感觉真的是收益匪浅,如果你有看源码的学习习惯[5],真的会学到很多~ 例如其实 Redux.compose中也用到了reduce。真的感觉有些代码,如果我从没有见到过,我绝对写不出来...

关于本文

来自:前舟

https://juejin.cn/post/7102591881204203557


作者:前舟


欢迎关注微信公众号 :前端Q