JS 数组的几个遍历方法你都会用的吧

1,453 阅读5分钟

photo © screenrant.com

🎼 前言

希望这篇文章对你来说都能是废话。

面试前端候选人的时候,我特别喜欢问两个方面的问题,一是基础知识,二是代码习惯。我认为,只有基础知识扎实的人才会对代码中的臭味敏感,而代码习惯好的才会有意识地去避免代码发臭。

其中数组的诸多遍历方法,是我必问的基础知识。

JS 的数组有多少原生遍历方法?每个方法的作用是什么?什么情况下用哪个方法最合适?

我见过很多前端新人,甚至不少顶着「资深」、「专家」头衔的同学,在数组遍历方法的使用上有着各种各样的问题,让读代码的我气不打一处来:

  • 有凡事求告 lodash 的(可能完全不知道原生的 Array 就可以做到)
  • 有拿 mapforEach 用的(我敢判断他纯粹是英语差)
  • 甚至有拿 filterforEach
  • 有认为在 forEachreturn 会跳出循环的
  • 有不知道 reduce 怎么用的

其中,拿 mapforEach 用是我见过最多的问题。

map 的效率一定是比 forEach 差的,因为它还要创建新数组,往新数组里插数据。但我不拿效率说事,对于目前的电脑性能来说,数据量没有达到一定的程度,这点效率消耗用户是完全感知不到的。我只论语义性,拿 mapforEach 使,跟你跟我说给我点外卖,却自己刷了半天抖音一个道理。

适合读者

  • 前端开发
  • 不清楚数组有多少遍历方法的
  • 瞎用数组遍历方法,随心所欲、毫无章法的

编辑历史

日期版本说明
2023/09/08V1

🎗️ 完全 / 非完全遍历

数组的遍历方法,是指这个方法接收一个回调函数作为参数,这个回调函数 起码 会接收到当前值、当前位置和数组本身作为参数。

for 循环可以 break 不一样,数组遍历方法是否能够跳出循环,是不能在语法层面控制的。有的方法一定会在全部遍历完成后才结束,有的则有可以中途提前结束循环。

因此,遍历方法可以分为「完全遍历」和「非完全遍历」两种。

方法完全遍历
forEach
filter
map
some
every
find
findLast
findIndex
findLastIndex
reduce
reduceRight

🎋 遍历方法选择策略

如何选择合适的遍历方法,是体现你基础知识是否扎实,保证不让维护者在这方面唾弃你的代码的关键。

我之前带过几个人做项目,对 CR 中重复指出数组方法问题不厌其烦,于是我画了一个图给他们,让他们以后不会选合适的方法时对照着看:

假设原数组类型为 Array<T>,则根据以下步骤选择方法:

  1. 仅遍历,不需要返回结果,看是否需要提前跳出循环
  1. 返回结果类型依然为 Array<T>filter
  2. 返回结果类型为非 T 数组,看结果长度与原数组是否相同
  1. 返回结果类型为 T | undefinedfind / findLast
  2. 返回结果类型为 booleansome / every
  3. 返回结果类型为 number,是否和元素位置有关
  1. 返回结果类型为其他(字符串、对象等) → reduce / reduceRight

其中,forEach 本身就没有返回值;别的方法,除了 some 可以偶尔忽略返回值之外,若忽略其返回值,则代码一定有问题。

仅遍历,不需要返回结果

不需要提前结束循环

毫无疑问用 forEach

当然,这里也可以用 forfor..infor..of 等。还是那句话,在数量级没有达到一定程度的情况下,谈 forEach 的性能没有这些好,是毫无意义的。

需要提前结束循环

some,忽略其返回值。

你说用 every 也可以?没错,但代码会难以理解,为了代码的可读性和一致性,请用 some。也就是说,当 every 的返回值被忽略的时候,说明代码有问题。

当然,这里也可以用带 breakforfor..infor..of

返回结果类型依然为 Array<T>

毫无疑问用 filter

返回结果类型为非 T 数组

结果长度与原数组相同

一个数组生一个不同类型,相同长度的数组,毫无疑问用 map

结果长度与原数组不同

一个数组生一个不同类型,且不同长度的数组,用 reduce / reduceRight

返回结果类型为 T | undefined

其实就是「找到一个元素」或者「找不到」,用 find / findLast

如果你喜欢 .filter(...)[0],那么恭喜你,基础知识不过关。

返回结果类型为 boolean

some / every

你说 includes?很好,能用的时候用它,但它严格来说不是本文所说的带回调的「遍历」方法。

再一句,includesarr.indexOf(o) >= 0 要好的多。

返回结果类型为 number

跟元素位置有关

找元素的位置,用 findIndex / findLastIndex

你又说 indexOf / lastIndexOf?又很好,能用就用,但它们又严格来说不是本文所说的带回调的「遍历」方法。

跟元素位置无关

比如,把所有元素对象中的某个数值相加得到一个总数,用 reduce / reduceRight

返回结果类型为其他

reduce / reduceRight

🧮 来点统计

以下是我的一个项目下的统计数据,非权威数据。

map 真的用的很多,尤其是在有接口数据处理的时候。

🪭 写在最后

虽然,这篇文章对多数人来说都是废话,可我还是希望作为前端开发,可以沉下心来好好夯实基础,优化自己的编码习惯。

如果,你看了这篇文章觉得毫无收获,那么恭喜你。