JavaScript 提供了多种遍历数组的方式,主要分为循环结构 和数组迭代方法。
常见方法列表:
for循环 (基础循环)for...of(ES6,推荐)forEachmapfiltersomeeveryreduce/reduceRightfind/findIndex
他们有什么不同呢?
想象你是一个包工头 ,你手底下有一排工人 (这就是数组 Array),你需要给他们派活儿。
JavaScript 提供了好多不同的"管理模式"来遍历这些工人,咱们来看看它们各自的性格:
1. 遍历数组的"管理模式"大赏
👴 for 循环 & for...of ------ "亲力亲为的老老板"
这是最传统、最听话的模式。
- 特点 :你指哪打哪。你可以随时喊停(
break),也可以跳过某个人(continue)。 for...of(推荐) :是 ES6 新来的帅气经理,语法简洁,专门用来遍历"可迭代"的东西(数组、字符串等)。- 场景:你需要绝对的控制权,或者需要按顺序一个个盯着做。
🤖 forEach ------ "一根筋的监工"
- 特点 :一旦启动,绝不回头。他会逼着每个工人都干一遍活,不管你中途是不是想停下来,他都听不见。
- 缺点 :不能中断! 哪怕你找到想要的了,他也得把剩下的人过一遍。
- 场景:只是简单地让每个人干点事(比如打印一下日志),不需要返回值,也不需要中途退出。
🏭 map ------ "加工流水线"
- 特点 :进一出一。进去 10 个原料,出来 10 个成品。它不会修改原来的工人,而是生成一个新的数组(成品堆)。
- 场景 :你需要把数据"变身"。比如把
[1, 2, 3]变成[2, 4, 6]。
🕵️ filter ------ "面试官 / 筛选器"
- 特点 :优胜劣汰。符合条件的留下,不符合的踢走。返回一个新的、可能变短的数组。
- 场景:从一堆数据里挑出你想要的。比如"只要大于 18 岁的"。
🎯 find ------ "寻宝猎人"
- 特点 :找到就跑。他只找第一个符合条件的人,一旦找到,立马拿着结果下班,后面的人看都不看。
- 场景:找唯一的那个 ID,或者找第一个及格的人。
🍬 reduce ------ "收纳大师 / 揉面团"
- 特点 :九九归一。把一堆东西揉成一个东西。比如把一堆数字加成一个总和,或者把一堆对象合并成一个大对象。
- 场景:算总价、统计个数。这是最难理解但也最强大的方法。
2. 灵魂拷问一:谁能按"暂停键"?(中断)
想象一下,你正在在一堆石头里找金子。
-
✅ 能暂停 (
break/return) :for、for...of:找到金子了?直接break走人,效率最高。find、some、every:这些方法内置了"满足条件就停止"的机制。
-
❌ 不能暂停 (必须跑完全程) :
forEach:哪怕第一个就是金子,它也要把后面所有的石头都摸一遍。千万别在forEach里写break,会报错!map、filter:它们是流水线,必须处理完所有原料。
3. 灵魂拷问二:谁能搞定"拖延症"?(异步 Async/Await)
想象每个工人干活都需要时间(比如去服务器拿数据,需要等 1 秒)。
-
✅
for...of------ "守秩序的排队者"- 如果你在
for...of里面用await,它会乖乖排队。等第一个人干完(1秒),再让第二个人干(1秒)。 - 结果:顺序执行,总时间 = 人数 × 1秒。
- 如果你在
js
// 就像排队结账,一个结束下一个上
for (const item of list) {
await doSomething(item); // ✅ 真的会等!
}
-
❌
forEach------ "乱成一锅粥"forEach是个急性子。它会瞬间对所有人喊"开始!",然后自己就溜了。它根本不会等await。- 结果:所有人同时开始干,顺序乱套,而且你没法知道他们什么时候全部干完。
js// ❌ 错误示范 list.forEach(async (item) => { await doSomething(item); // 😱 forEach 根本不理你,直接跑下一个去了 }); -
⚡️
map+Promise.all------ "并发大神"- 如果你想让大家一起干(并发),最后再一起收工。
- 结果:同时开工,总时间 ≈ 最慢的那个人花的时间。
js// 大家一起上! await Promise.all(list.map(async item => { await doSomething(item); }));
总结一下(新手小抄):
-
只是想遍历,或者需要
break👉 用for...of(最稳)。 -
想把数据变个样 👉 用
map。 -
想过滤数据 👉 用
filter。 -
想找某一个 👉 用
find。 -
里面有
await异步操作:- 要顺序 执行 👉
for...of。 - 要并发 执行 👉
map+Promise.all。 - 千万别用
forEach!
- 要顺序 执行 👉
速记
关于中断(break/return)的支持
支持中断(break / return)的方法:
for循环for...of循环for...in循环 (不推荐用于数组)some(通过返回true停止)every(通过返回false停止)find/findIndex(找到目标即停止)
不支持中断(无法通过 break/return 提前结束)的方法:
forEach(必须遍历完所有元素,除非抛出异常)mapfilterreduce
关于异步遍历(Async/Await)的支持
这是一个常见的坑。
支持异步等待(能按顺序 await)的方法:
for循环for...of循环
不支持异步等待(无法在回调中正确 await)的方法:
forEach:它会立即启动所有回调,不会等待前一个回调的await完成。map:它会返回一个 Promise 数组,需要配合Promise.all使用,但它是并发执行的,不是顺序执行。filter,reduce等高阶函数在配合 async 使用时通常无法达到预期效果(例如filter无法根据异步结果过滤)。