fill([]) 会出问题是因为填入的是同一数组引用,导致所有子项共享内存;正确方式是每次生成新引用,如 Array.from({length:3},()=>[])。

用 Array.prototype.fill() 初始化多维数组时,若直接填入同一个引用(比如空数组 []),所有子项会共享同一内存地址——这不是“复制”,而是“贴标签”。稍后修改任一子数组,其他行全跟着变,Bug 就藏在这儿。
为什么 fill([]) 会出问题?
fill() 填的是值,但对象(包括数组)的“值”本质是引用。写 new Array(3).fill([]),相当于创建一个空数组,再把它的地址复制三份,放进新数组里。结果是:
- 三个索引位置指向同一个数组实例
-
arr[0].push(1)→arr[1]和arr[2]也立刻包含1 - 看似“二维”,实则“一层半”:外层数组独立,内层数组完全共用
正确初始化多维数组的三种方式
核心原则:每次都要生成**新的引用**,不能复用旧对象。
-
用 Array.from + map(推荐):
Array.from({ length: 3 }, () => [])—— 每次回调都执行一次() => [],生成独立空数组 -
用 for 循环手动 push:
const arr = []; for (let i = 0; i —— 显式控制每次新建 -
用 Array.from 配合索引(需带默认值):
Array.from({ length: 3 }, (_, i) => new Array(4).fill(null).map(() => []),适合更深层嵌套
常见误用场景与修复对比
比如想建一个 3×4 的空格二维表,用于井字棋或矩阵计算:
- ❌ 错误写法:
const board = new Array(3).fill(new Array(4).fill(null))→ 所有行引用同一列数组 - ✅ 正确写法:
const board = Array.from({ length: 3 }, () => new Array(4).fill(null))→ 每行都是新数组,每格独立 - ? 进阶提醒:如果格子要存对象(如
{ occupied: false }),仍需用map(() => ({ occupied: false }))确保每个对象都是新实例
如何快速检测是否掉进引用陷阱?
在初始化后加一行简单验证:
- 修改第一行第一格:
arr[0][0] = 'X' - 检查第二行第一格:
console.log(arr[1][0]) - 若输出
'X',说明仍在共享引用,需重构初始化逻辑 - 也可用
Object.is(arr[0], arr[1])直接判断两行是否为同一引用

















