删除数组中非数字元素的代码异常:调换元素位置结果不同的原因
数组删除非数字元素时的遍历异常解析
问题场景
尝试编写代码删除数组中的非数字元素,第一段代码执行后输出不符合预期,仍存在非数字元素:
let arr = [1, "5", 3, 27, undefined, { name: 'Steven' }, 11]; for (let i = 0; i < arr.length; i++) { if (typeof arr[i] !== 'number') { arr.splice(i, 1); } } console.log(arr); // 输出: [1, 3, 27, {…}, 11]
调换数组中对象与最后一个数字的位置后,输出结果正常:
let arr = [1, "5", 3, 27, undefined, 11, { name: 'Steven' }]; for (let i = 0; i < arr.length; i++) { if (typeof arr[i] !== 'number') { arr.splice(i, 1); } } console.log(arr); // 输出: [1, 3, 27, 11]
原因解析
核心问题在于正序遍历数组时使用splice删除元素,会导致数组长度缩短、后续元素索引前移,而循环的i仍在递增,直接跳过了被前移的元素。
第一个例子的执行细节
- 初始数组:
[1, "5", 3, 27, undefined, { name: 'Steven' }, 11] i=1时,元素"5"是非数字,执行splice(1,1),数组变为[1, 3, 27, undefined, { name: 'Steven' }, 11],随后i自增到2i=3时,元素undefined是非数字,执行splice(3,1),数组变为[1, 3, 27, { name: 'Steven' }, 11],i自增到4- 此时
i=4对应的元素是11(数字),循环继续直到i等于数组长度(5),循环结束。原本在undefined后的对象被移到了索引3的位置,但i已经跳到4,完全跳过了对这个对象的检查,所以它留在了数组里。
第二个例子的执行细节
- 初始数组:
[1, "5", 3, 27, undefined, 11, { name: 'Steven' }] - 前面步骤类似,删除
"5"和undefined后,数组变为[1, 3, 27, 11, { name: 'Steven' }] i=4时,元素是对象(非数字),执行splice(4,1),数组长度变为4,i自增到5,此时i < arr.length不成立,循环结束,所有非数字元素都被处理完毕。
解决方法
方法1:倒序遍历
从数组末尾开始遍历,即使删除元素,前面的元素索引不受影响,不会出现跳过的情况:
let arr = [1, "5", 3, 27, undefined, { name: 'Steven' }, 11]; for (let i = arr.length - 1; i >= 0; i--) { if (typeof arr[i] !== 'number') { arr.splice(i, 1); } } console.log(arr); // [1, 3, 27, 11]
方法2:使用filter方法(推荐)
filter方法会返回一个新数组,包含所有符合条件的元素,逻辑更直观且不会修改原数组:
let arr = [1, "5", 3, 27, undefined, { name: 'Steven' }, 11]; const numArr = arr.filter(item => typeof item === 'number'); console.log(numArr); // [1, 3, 27, 11]
内容的提问来源于stack exchange,提问作者andrijadenic9
相关产品推荐
相关产品推荐

