使用forEach循环删除数组元素时,为何未被删除的元素未在控制台打印?
为什么在forEach中删除数组元素后,控制台只打印了部分元素?
这问题挺典型的,我来给你掰扯清楚为啥会出现这种情况~
先看你的代码:
const cartItems = ['Book1', 'Book2', 'Book3', 'Book4'] cartItems.forEach(function (item, index, array) { console.log(item) if (index == 0) { array.shift() } if (index == 1) { array.splice(1, 1) } }) console.log(cartItems)
你预期forEach会遍历所有4个元素,但实际只打印了Book1和Book3,剩下的Book2和Book4没出现在控制台,核心原因是你在遍历过程中修改了数组的结构(删除元素),打乱了forEach的遍历逻辑。
一步步拆解你的代码执行过程:
- 初始数组:
['Book1','Book2','Book3','Book4'],长度为4。forEach启动时,会按索引从0到3依次准备遍历。 - 第一次循环(index=0):
- 打印
Book1 - 执行
array.shift(),数组被修改为['Book2','Book3','Book4'],长度变成3。
- 打印
- 第二次循环(index=1):
- 注意!此时数组已经变了,当前index=1对应的元素是原来的
Book3(原来的Book2现在跑到index=0的位置了) - 打印
Book3 - 执行
array.splice(1,1),删除当前index=1的元素(也就是Book3),数组变成['Book2','Book4'],长度变成2。
- 注意!此时数组已经变了,当前index=1对应的元素是原来的
- 第三次循环(index=2):
- 现在数组的长度是2,最大索引是1,index=2已经超出了数组的有效范围,forEach直接终止循环,不会再执行后续的遍历。
所以到最后,只有Book1和Book3被打印,而Book2(现在在index=0,但forEach不会回头遍历已经处理过的索引)、Book4(还没轮到遍历它循环就结束了)都没机会被打印出来。
本质原因:
forEach的遍历逻辑是按初始的索引序列(0到初始length-1)依次访问,但每次访问时会检查当前索引是否在数组的有效范围内。当你在遍历中删除元素,数组的长度和元素位置都会变化,导致后续索引要么指向错误的元素,要么直接超出范围终止循环。这种情况下,很容易出现遍历不完整或者漏处理/重复处理元素的问题。
正确的做法:
如果你想删除特定索引的元素,不建议在forEach里操作,推荐这两种更稳妥的方式:
- 使用filter方法(最简洁):
直接筛选出不需要删除的元素,返回新数组,不会修改原数组:const cartItems = ['Book1', 'Book2', 'Book3', 'Book4']; const filteredItems = cartItems.filter((_, index) => index !== 0 && index !== 2); console.log(filteredItems); // 输出 ['Book2', 'Book4'] - 倒序删除元素:
如果一定要修改原数组,从后往前删除元素,这样前面的元素索引不会被打乱:const cartItems = ['Book1', 'Book2', 'Book3', 'Book4']; // 把要删除的索引从大到小排序,倒序遍历删除 [0, 2].sort((a, b) => b - a).forEach(index => cartItems.splice(index, 1)); console.log(cartItems); // 输出 ['Book2', 'Book4']
内容的提问来源于stack exchange,提问作者Muhammad Ali Malekzadeh
相关产品推荐
相关产品推荐

