为何在迭代中使用Array.prototype.slice会出现不符合预期的行为?
数组前缀生成的for-in循环异常问题解析
问题重现
我们需要生成数组的「前缀数组」(依次包含第1个、前2个……全部N个元素的数组),初始代码及结果如下:
const arr = [1,2,3,4,5] for (const i in arr) console.log(i, arr.slice(0, i)) // 输出结果: // 0, Array [] // 1, Array [ 1 ] // 2, Array [ 1, 2 ] // 3, Array(3) [ 1, 2, 3 ] // 4, Array(4) [ 1, 2, 3, 4 ]
结果不符合预期:i=0时期望得到[1],i=4时期望得到[1,2,3,4,5]。修改为arr.slice(0, i+1)后出现异常:
for (const i in arr) console.log(i, arr.slice(0, i+1)) // 输出结果: // 0, Array [ 1 ] // 1, Array(5) [ 1, 2, 3, 4, 5 ] // 2, Array(5) [ 1, 2, 3, 4, 5 ] // 3, Array(5) [ 1, 2, 3, 4, 5 ] // 4, Array(5) [ 1, 2, 3, 4, 5 ]
手动调用arr.slice(0, 3)能得到预期的[1,2,3],但循环中却出现异常。
问题原因
核心问题在于for-in循环遍历数组时,得到的索引i是字符串类型,而非数字类型:
- 执行
i+1时,不是数字加法,而是字符串拼接:比如i为"1"时,i+1得到的是"11",而非数字2; Array.slice()方法会自动将第二个参数转为数字,但"11"转成数字后远大于数组长度5,此时slice会直接截取到数组末尾,因此得到整个数组。- 手动调用时传入的是数字3,自然能得到正确的前缀数组。
解决方法
有几种可行的修复方式:
- 将索引转为数字后再计算:
const arr = [1,2,3,4,5] for (const i in arr) console.log(i, arr.slice(0, Number(i)+1)) // 输出符合预期: // 0, Array [ 1 ] // 1, Array [ 1, 2 ] // 2, Array [ 1, 2, 3 ] // 3, Array(4) [ 1, 2, 3, 4 ] // 4, Array(5) [ 1, 2, 3, 4, 5 ]
也可以用+i快速转数字:arr.slice(0, +i +1)。
- 使用普通for循环(更推荐遍历数组):
const arr = [1,2,3,4,5] for (let i = 0; i < arr.length; i++) { console.log(i, arr.slice(0, i+1)) }
- 使用for-of循环结合数组的entries方法:
const arr = [1,2,3,4,5] for (const [i] of arr.entries()) { console.log(i, arr.slice(0, i+1)) }
内容的提问来源于stack exchange,提问作者Dylan
相关产品推荐
相关产品推荐

