js遍历那些事儿
次访问
本文总结js中的各种常用遍历。
基本用法
for
最基本的遍历写法,通过索引来遍历。
1 | let arr = [1, 2, 3] |
forEach
写法比for简便,遍历所有元素,不返回任何值。
1 | let arr = [1, 2, 3] |
map
映射,常用于基于原数组返回新数组(不改变原数组)。
1 | let arr = [1, 2, 3] |
filter
筛选,常用于过滤原数组来产生新数组,不改变原数组。
1 | let arr = [1, 2, 3] |
以上4种遍历基本满足大部分需求,下面看一些用的较少的遍历方法。
reduce
将数组中的元素逐个进行处理,并将它们合并为一个值。功能十分强大,回调函数可以进行各种复杂的操作,包括条件判断、对象构建等。
语法:
1 | array.reduce(function(total, currentValue, currentIndex, arr), initialValue) |
- callback (执行数组中每个值的函数,包含四个参数)
- total- 必需 (初始值, 或者计算结束后的返回值)
- currentValue - 必需 (数组中当前被处理的元素)
- currentIndex - 可选 (当前元素在数组中的索引)
- arr - 可选 (调用 reduce 的数组)
- initialValue - 可选 (作为第一次调用 callback 的第一个参数,如果不提供,第一次回调会使用数组的第一个元素)
示例(最简单的累加):
1 | let arr = [1, 2, 3] |
比如我们要统计字符串中每个字母出现的次数:
1 | const arrString = 'abcdaabc' |
every
条件都满足返回true。
1 | let arr = [1, 2, 3] |
some
有一个条件满足返回true。
1 | let arr = [1, 2, 3] |
for…in
主要用于遍历对象的可枚举属性(还会遍历原型链上的可枚举属性)。
遍历数组(不推荐,会遍历数组的所有可枚举属性,包括非索引属性和原型链上的属性):
1 | let arr = [1, 2, 3] |
遍历对象:
1 | let obj = { a: 1, b: 2, c: 3 } |
for…of
用于遍历可迭代对象(例如 Array, Map, Set, String, TypedArray,NodeList以及其他 DOM 集合,arguments 对象等)的可迭代属性(不可迭代属性会被忽略)。
1 | const arr = [1, 2, 3]; |
for...in和for...of的区别:
1 | Object.prototype.objCustom = function () {} |
可以看到,主要有3点不同:
- 1.
for...in遍历key,for...of遍历value - 2.
for...in遍历的是可枚举属性,for...of遍历的是可迭代属性 - 3.对于array的不可迭代元属性
objCustom、arrCustom和实例属性foo,在for...of循环中都被忽略
Object.keys,values,entries
对于普通对象(需要注意和map的区别):
- Object.keys(obj):返回一个包含该对象所有的键的数组。
- Object.values(obj):返回一个包含该对象所有的值的数组。
- Object.entries(obj):返回一个包含该对象所有 [key, value] 键值对的数组。
1 | let user = { |
Object.entries把 obj 变成由键/值对组成的数组,然后使用 Object.fromEntries可以将结果转回成原来的对应
1 | let user = { |
中断循环
中断循环,推荐使用break,continue不退出循环,只跳过当前循环,if条件判断替换continue,可读性更高。
for循环(for/for...in/for...of)可通过break退出循环。
1 | let arr = [1, 2, 3] |
总结,有
for关键字时,可以通过break退出循环,forEach可以通过throw Error的方式退出循环(但不推荐这样写,推荐用for)。
异步
当遍历碰到async、 await、 Promise时,又该怎么写呢?
1 | let arr = [20, 10, 30] |
上面有个数组arr和耗时操作sleep,如果没有耗时操作,就是下面同步的写法:
1 | const syncRes = arr.map((i) => { |
如果有耗时操作,像下面这样,怎么保持输出还是[20, 10, 30]呢?
1 | await sleep(i) |
最简单的方法可以用for循环(for/for...in/for...of都一样):
1 | let asyncRes1 = [] |
map可以像这样Promise.all(arr.map(async (...) => ...)):
1 | const asyncRes = await Promise.all(arr.map(async (i) => { |
如果不用Promise.all,就是下面的效果:
1 | const asyncRes = arr.map(async (i) => { |
碰到reduce时async (prev, cur) => await prev:
1 | const asyncRes = await arr.reduce(async (prev, cur) => { |
在forEach、filter等其他循环中需要使用异步,先用map、reduce、for...of处理。
总结
- 基本用法要熟记特性,灵活选用
- 需要中断就用for(
for/for...in/for...of),使用break退出 - 碰到异步用for(
for/for...in/for...of)/map/reduce