JavaScript中for循环何时需用递减操作?以数组元素移除场景为例
关于数组移除元素时for循环递减操作的疑问
我在Odin Project的练习中需要实现一个移除数组指定元素并返回新数组的函数,先写了一段能运行但不够优雅的代码:
const removeFromArray = function(myArray, ...elements) { for (let i = 0; i < myArray.length; i++){ if (elements.includes(myArray[i])){ myArray.splice(i,1); i--; // 此处为疑问点 } } return myArray; };
如果去掉这个递减操作,结果会出错:
myArray = [1,2,3,4]; elements = [1,2,3,4]; result = [2,4] expected = []
我明白这是因为splice移除元素后后续元素会前移,导致跳过了下一个元素。之后看到官方提供了更简洁的forEach实现:
const removeFromArray = function (myArray, ...elements) { const newArray = []; myArray.forEach((item) => { if (!elements.includes(item)) { newArray.push(item); } }); return newArray; };
我想请教两个问题:
- 这种在for循环中用递减的写法有没有适用场景,还是应该始终选更优雅的实现方式?
- 在JavaScript的for循环里,有没有必须使用递减操作的情况?
问题解答
循环递减写法的适用场景
你写的原地修改数组的循环递减写法并非不能用,但仅适用于特定场景:
- 当必须原地修改原数组(比如原数组是外部引用,要求不能创建新数组),同时需要遍历移除元素时,这种写法是可行的。但要注意,原地修改数组可能带来副作用,比如影响其他依赖该数组的代码。
- 相比之下,官方的forEach写法是创建新数组,属于纯函数(不修改输入,返回新值),更符合函数式编程风格,可读性和可维护性更高,大多数业务场景中更推荐使用。
必须使用递减操作的for循环场景
在JavaScript中,确实存在需要使用递减操作的情况:
- 正向遍历并原地删除数组元素:如你遇到的情况,当用
splice从前往后删除元素时,后续元素会前移,如果不递减索引,会跳过下一个元素,导致漏删。 - 反向遍历逻辑需求:比如需要倒序处理数组元素,或从最后一个元素开始执行操作(如链表反向遍历模拟、某些算法题的特定要求),这时会使用
i--的循环方式。 - 极端性能优化场景:在处理超大数组时,原地修改比创建新数组更节省内存,若选择正向遍历删除元素,就必须配合索引递减。不过这种场景在前端日常开发中极少出现。
额外优化方案
其实原地删除元素时,还有一种更直观的写法——反向遍历数组,不需要调整索引:
const removeFromArray = function(myArray, ...elements) { for (let i = myArray.length - 1; i >= 0; i--) { if (elements.includes(myArray[i])) { myArray.splice(i, 1); } } return myArray; };
这种写法避免了索引递减的操作,逻辑更清晰,同样能实现原地删除的需求。
日常开发中,还可以用更简洁的filter方法实现:
const removeFromArray = function(myArray, ...elements) { return myArray.filter(item => !elements.includes(item)); };
它本质和forEach写法一致,都是创建新数组,代码更简洁易读。
内容的提问来源于stack exchange,提问作者Christopher Benner
相关产品推荐
相关产品推荐

