很多人始终不明白,ES6 数组的遍历方法最重要的不在代码本身,而是语义化!map、reduce、filter、some、every、find ...
前言
不知不觉,ES6 的数组新语法已经出了好多年了,大家都应该理解一句话: ES6 数组方法带来的最大优势是语义化 。
很多人在使用 ES6 数组语法时,将它当作了便捷操作。
甚至更多千奇百怪的用法,我希望大家在看完该文章后,去检查一下自己的项目中,这些语法是否可以一眼让大家看出这些方法是做什么用的。
反面操作
这里简单列举一些反面操作:
- 将
map
作为循环使用,通过map
计算总数
const arr = [{..., count: 1}, {..., count: 5}]
let total = 0;
arr.map(v => {
total += v.count
})
- 将
map
作为循环使用,改变数组中的对象的属性
// 操作1
let arr = [{..., id: '1'}, {..., id '2'}]
arr = arr.map(v => ({...v, id: Number(id)}))
// 操作2
let arr = [{..., id: '1'}, {..., id '2'}]
arr.map(v => {
v.id = Number(v.id)
})
其中尤其是改变对象属性中的操作1,是误用最多的用法。
讲解
我一般不做基本语法讲解,因为罗列式的讲解让你左脑进右脑出,不带给大家任何价值。面向实际的使用才能让大家影响深刻。
接下来,我将假设自己是一个快递站的老板,我作为一个快递站的老板,应该如何通过这些语法来处理我的快递。
为了让代码更清晰,我将以 ed 来作为快递的简称(express delivery)
map
语义 :将一些东西转换为另一些东西。
正面示例: 我需要将所有的 快递单号 + 派送时间 整理出来,来决定我的送货顺序。
const edArr = [{..., id: '666666666', date: '2024-02-23'}, {..., id: '666666688', date: '2024-02-22'}, ...]
const data = edArr.map(v => ({id: v.id, date: v.date}))
反面示例: 我希望给所有快递贴一个广告。
虽然反面案例也能实现,并且也没有代码量的提升,但是我强烈不建议这么干。这会大大降低你代码的可阅读性。
foreach
语义:我希望循环做某些事。
显然,相较于 map
,上面的反面案例应该交由 foreach
操作,而正面案例则是 foreach
的反面案例。这两者大家常常是反着用的。
正面示例: 我希望给所有快递贴一个广告。
反面示例: 我需要将所有的 快递单号 + 派送时间 整理出来,来决定我的送货顺序。
const edArr = [{..., id: '666666666', date: '2024-02-23'}, {..., id: '666666688', date: '2024-02-22'}, ...]
const data = []
edArr.foreach(v => {
data.push({id: v.id, date: v.date})
})
filter
语义:我希望筛选出来一些东西。
正面示例: 我希望找到所有用户拒收的快递,发回给快递公司。
const edArr = [{..., reject: false}, {..., reject: true}, ...]
const rejectEdArr = edArr.filter(v => v.reject === true)
反面示例:
我希望找到单号为 8888
的快递。
const edArr = [{..., id: '6666'}, {..., id: '8888'}, ...]
const nArr = edArr.filter(v => v.id === '8888')
显而易见的是,快递单号是唯一的,用 filter 在这里是不合适的。 因为它最多筛选出一个符合条件的快递,且这个一是已知的。
find
语义:找一个符合条件的给我。
正面示例: 快递员:我车装差不多了,再给我一个 270号楼 的快递,我一块儿送过去。
const edArr = [{..., address: '271'}, {..., address: '270'}, ...]
const oneEd = edArr.find(v => v.address === '270')
反面示例: 顾客:今天有没有我的快递?
const edArr = [{..., user: 'zhangsan'}, {..., user: 'sincenir'}, ...]
const ed = edArr.find(v => v.user === 'sincenir')
if (ed) {
// 有
} else {
// 没有
}
findIndex
语义:找符合条件的是第几个。
正面示例: 快递员:我今天还需要送多少快递?
const edArr = [{..., date: '2024-02-23'}, {..., date: '2024-02-24'}, ...]
const count = edArr.findIndex(v => v.date !== '2024-02-23') + 1
反面示例: 顾客:今天有没有我的快递?
const edArr = [{..., user: 'zhangsan'}, {..., user: 'sincenir'}, ...]
const haveSincenir = edArr.find(v => v.user === 'sincenir') > -1
这里需要提醒大家,
findIndex
是滥用极其严重的函数,包括有没有很多人都喜欢用findIndex
去做,这些都是不对的。 当你不知道你是否要使用findIndex
时,据我观察,大多数时候都应该使用别的语法。
some
语义:这里有没有符合条件的。
正面示例: 顾客:这里有没有我的快递?
const edArr = [{..., user: 'zhangsan'}, {..., user: 'sincenir'}, ...]
const haveSincenir = edArr.some(v => v.user === 'sincenir')
every
语义:这里是否全符合条件。
正面示例: 快递员:今天还有没有需要送的快递啦?
const edArr = [{..., date: '2024-02-23'}, {..., date: '2024-02-24'}, ...]
const haveToday = edArr.every(v => v.date !== '2024-02-23')
reduce
语义:基于这些帮我算一个东西。
正面示例: 咱们今天收的快递总共多少钱啊?我算算账对不对。
const edArr = [{..., amount: '13'}, {..., amount: '20'}, ...]
const totalAmount = edArr.reduce((r, v) => (r + v.amount), 0)
最后
语义化最重要的点在于,我们看到代码的第一眼,不需要看细节就能明白我们究竟准备做什么。 而不是为了便捷去使用这些方法,否则你的代码依旧是面条形状的面向过程编程。
最后我们总结下所有语法的语义:
- map: 将一些东西转换为另一些东西
- foreach: 我希望循环做某些事
- filter: 我希望筛选出来一些东西
- find: 找一个符合条件的给我
- findIndex: 找符合条件的是第几个
- some: 这里有没有符合条件的
- every: 这里是否全符合条件
- reduce: 基于这些帮我算一个东西
转载自:https://juejin.cn/post/7338397590008283175