为何使用forEach遍历数组时会跳过偶数索引元素?
为什么用forEach遍历数组删除元素时会跳过偶数索引?
这个问题我之前踩过一模一样的坑!核心原因在于forEach的遍历机制和数组动态修改之间的冲突,咱们一步步拆解清楚:
1. forEach的底层遍历逻辑
forEach在执行的瞬间,就会先记录数组的初始长度,然后严格按照索引从0到初始length-1的序列依次遍历。也就是说,它的遍历计划是一开始就定死的,不会因为遍历过程中数组的长度、元素位置变化而动态调整索引。
2. 模拟你的场景(用具体例子看过程)
假设你的数组b初始是[1,2,3,4,5,6],你在forEach里写了类似这样的删除逻辑:
b.forEach((item, index) => { // 简化条件:直接删除当前索引的元素 b.splice(index, 1); });
咱们一步步走一遍遍历流程:
- 初始状态:数组长度6,forEach要遍历的索引是0、1、2、3、4、5
- 索引0:删除元素1,数组变成
[2,3,4,5,6](长度缩为5) - 索引1:此时数组的索引1对应原本的元素3(因为元素2前移到了索引0),删除它后数组变成
[2,4,5,6](长度缩为4) - 索引2:数组的索引2对应原本的元素5(元素4前移到了索引1),删除它后数组变成
[2,4,6](长度缩为3) - 索引3:此时数组长度只有3,索引3已经超出了数组的有效范围,forEach直接终止遍历,剩下的
2,4,6完全没被处理到
你看,原本要处理6个元素,实际只处理了3个(索引0、1、2),正好是一半;而被跳过的都是原本的偶数索引元素(2、4、6)——因为它们在前面元素被删除后前移了位置,但forEach的索引还在按原顺序推进,直接跳过了这些移位后的元素。
3. 本质总结
forEach的设计初衷就是不支持在遍历过程中修改数组结构(比如删除/添加元素),它会基于初始的数组快照来执行遍历。如果一定要在遍历中修改数组,更稳妥的方式是倒序遍历(从后往前删,不会影响未遍历的索引),或者用filter生成新数组(更符合函数式编程的无副作用原则)。
内容的提问来源于stack exchange,提问作者DonJoe
相关产品推荐
相关产品推荐

