JavaScript中destroyer函数splice删数组元素结果异常修复
错误根因
你当前的for循环搭配splice的写法不符合预期,核心问题是数组调用splice删除元素后会发生原位塌陷:删除下标i的元素后,i后面所有元素都会自动往前移动1位,数组长度减1,但循环的计数变量i还是会照常执行i++自增,直接跳过了被删位置后紧跟的第一个元素,导致漏判。
拿你的测试用例destroyer([3, 5, 1, 2, 2], 2, 3, 5)走一遍执行流程就能直观看到问题:
- 初始i=0,
arr[0]是3,属于待删除值,执行splice后数组变为[5,1,2,2],随后i自增到1 - 此时i=1对应的元素是1,本来待删除的5因为数组前移到了下标0的位置,直接被跳过
- 后续遍历到i=2时元素是2,执行splice删除后数组变为
[5,1,2],i自增到3,超出当前数组长度(长度为2),循环直接结束,最终返回结果错误。
修复代码
保留for循环+splice的实现逻辑,有两种成熟的改法:
方案1:倒序遍历数组
从数组最后一个元素往前遍历,此时删除当前下标的元素,不会影响还没遍历到的前面元素的下标,不会出现漏判:
function destroyer(arr, ...rem) { for(let i = arr.length - 1; i >= 0; i--) { if (rem.includes(arr[i])) { arr.splice(i, 1); } } return arr; } console.log(destroyer([3, 5, 1, 2, 2], 2, 3, 5)); // 输出 [1],符合预期
方案2:正序遍历时删除元素后回退下标
如果要保留正序遍历的写法,每次执行splice删除后把i减1,抵消元素前移带来的下标偏移:
function destroyer(arr, ...rem) { for(let i = 0; i < arr.length; i++) { if (rem.includes(arr[i])) { arr.splice(i, 1); i--; // 回退下标,避免跳过紧接的元素 } } return arr; } console.log(destroyer([3, 5, 1, 2, 2], 2, 3, 5)); // 输出 [1],符合预期
你提到的
arr.filter(val => !rem.includes(val))是更推荐的实现方式:不会修改原数组,没有下标偏移的隐式问题,代码可读性更高。
内容的提问来源于stack exchange,提问作者pdostonh
相关产品推荐
相关产品推荐

