嵌套数组子数组元素添加疑问:为何Way3结果不符合预期?
嘿,这个问题其实戳中了JavaScript里引用类型的一个常见坑,咱们用大白话拆解清楚:
首先先还原下你说的方法3的典型写法(应该就是下面这种对吧?):
// 方法3的错误写法 let arrs = new Array(3).fill([]); for (let i = 0; i < 3; i++) { arrs[i].push(i + 1); } console.log(arrs); // 输出 [[1,2,3],[1,2,3],[1,2,3]]
问题出在哪?
JavaScript里的数组属于引用类型,你可以把它想象成一个储物柜:[]就是创建了一个新储物柜,而变量存的其实是这个储物柜的「钥匙」。
当你用new Array(3).fill([])的时候,你不是给数组的3个位置各配一把新储物柜的钥匙,而是把同一把钥匙复制了3份放进了数组的三个位置里。也就是说,arrs[0]、arrs[1]、arrs[2]指向的都是内存里的同一个储物柜。
所以你循环的时候,第一次给arrs[0]push 1,其实是往那个唯一的储物柜里放了1;第二次给arrs[1]push 2,还是往同一个储物柜里放2;第三次同理放3。最后三个位置的钥匙打开的都是那个装了1、2、3的储物柜,自然就得到了三个一模一样的数组。
为什么方法1、2没问题?
咱们对比下正确的写法就明白了:
- 方法1:每次循环都手动
push([]),相当于每次都新建一个储物柜,给数组的每个位置配一把新钥匙,彼此完全独立:
let arrs = []; for (let i = 0; i < 3; i++) { arrs.push([]); // 每次都生成新的空数组(新储物柜) arrs[i].push(i + 1); }
- 方法2:比如用
map生成数组,map的回调函数每次都会返回一个新的[],同样是给每个位置配独立的钥匙:
let arrs = new Array(3).map(() => []); for (let i = 0; i < 3; i++) { arrs[i].push(i + 1); }
修复方法3的正确姿势
如果想保持类似方法3的初始化方式,只要确保每个位置都是独立的数组就行,比如:
- 用
Array.from生成:
let arrs = Array.from({ length: 3 }, () => []);
- 用
map替代fill(注意空数组直接用map会跳过空位,所以先初始化长度再map是没问题的):
let arrs = new Array(3).map(() => []);
- 手动循环创建子数组,和方法1类似。
这样修改后,每个子数组都是独立的引用,再push元素就会得到你预期的[[1],[2],[3]]啦~
内容的提问来源于stack exchange,提问作者juanli
相关产品推荐
相关产品推荐

