JavaScript 二维数组初始化:为什么 fill([]) 是个大坑?
JavaScript 二维数组初始化:为什么 fill([])
是个大坑?
今天刷leetcode的时候,遇到一个神奇的bug。
当我修改数组中的一个元素,却意外影响了其他所有元素???。
问题重现:诡异的数组共享
const r = 3;
const mat = new Array(r).fill([]);
mat[0].push(1);
console.log(mat); // 输出什么?
我期望的输出可能是 [[1], [], []]
,但实际结果却是 [[1], [1], [1]]
!所有子数组都被修改了。
为什么会这样???
引用类型的陷阱
在 JavaScript 中,数组是引用类型。当我们使用 fill([])
时:
- 首先创建一个空数组
[]
(假设内存地址为 0x123) - 然后将这个引用复制到新数组的每个位置
内存结构如下:
mat: [0x123, 0x123, 0x123] │ │ │ ▼ ▼ ▼ [ ] [ ] [ ]
所有元素都指向同一个数组对象!
与原始类型的区别
对比使用原始类型的情况:
const arr = new Array(3).fill(0);
arr[0] = 1;
console.log(arr); // [1, 0, 0] 表现正常
因为原始类型(如数字)是直接存储值,而非引用。
正确的初始化方式O(∩_∩)O~
方法1:循环初始化
const mat = new Array(r);
for (let i = 0; i < r; i++) {mat[i] = [];
}
方法2:使用 map(推荐)
const mat = new Array(r).fill().map(() => []);
或者更简洁的:
const mat = Array.from({ length: r }, () => []);
总结
- 永远不要用
new Array(n).fill([])
初始化二维数组 - 引用类型在
fill()
中会被共享 - 使用
Array.from
或map
确保每个子数组独立
啊啊啊啊啊哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇