JS遍历数组调用splice删除元素时漏删重复值问题排查
destroyer函数逻辑bug修复
你当前的实现代码如下:
function destroyer(arr) { const newArr = [...arguments[0]] for(let i = 0; i < newArr.length; i++){ for(let j = 1; j < arguments.length; j++){ if(arguments[j] == newArr[i]){ newArr.splice(i,1) console.log(newArr) } } } } destroyer([3, 5, 1, 2, 2], 3, 5, 2);
错误原因
出现漏删第二个2的问题,核心是两个逻辑漏洞:
- 正向遍历+splice删除导致索引错位
当你在索引i位置执行splice(i,1)删除元素时,被删元素后方的所有元素会自动向前补位,原本在i+1位置的元素会移动到i位置。但外层循环每次结束都会执行i++,下一轮直接跳到i+1位置遍历,刚补位到i的元素会被直接跳过。
结合你的测试用例走一遍流程就能直观看到问题:- 初始数组:
[3,5,1,2,2],i=0时匹配到3,删除后数组变为[5,1,2,2],j循环继续执行时发现当前i=0位置的5也匹配删除规则,再次删除后数组变为[1,2,2] - 外层循环i自增到1,匹配到位置1的2,删除后数组变为
[1,2],此时原本在位置2的2补位到位置1 - 外层循环i继续自增到2,而当前数组长度为2,循环直接终止,补位到位置1的2完全没被遍历到,最终被留在数组里
- 初始数组:
- 缺少返回值
函数执行完没有return最终处理好的数组,外部无法直接获取结果,只能在函数内部通过console.log查看中间值。
修复方案
方案1:修正原有循环逻辑
删除元素后手动将索引i回退1位,保证下一轮循环能检查到补位到当前位置的元素,同时把要删除的目标值提前提取出来,减少不必要的嵌套循环:
function destroyer(arr) { const newArr = [...arguments[0]] const removeTargets = Array.from(arguments).slice(1) for(let i = 0; i < newArr.length; i++){ if(removeTargets.includes(newArr[i])){ newArr.splice(i, 1) i-- // 索引回退,避免跳过补位元素 } } return newArr } console.log(destroyer([3, 5, 1, 2, 2], 3, 5, 2)) // 输出[1],符合预期
方案2:用filter简化实现(推荐)
直接用数组原生filter方法过滤掉需要移除的元素,不需要手动维护遍历索引,逻辑更简洁,也不会出现索引错位问题:
function destroyer(arr) { const removeTargets = Array.from(arguments).slice(1) return arguments[0].filter(item => !removeTargets.includes(item)) } console.log(destroyer([3, 5, 1, 2, 2], 3, 5, 2)) // 输出[1]
内容的提问来源于stack exchange,提问作者kylemccranie
相关产品推荐
相关产品推荐

