fill(引用类型)必然导致引用共享,表现为修改一个元素影响其余、===返回true、调试器显示“same as”,应改用Array.from({length:n},()=>({}))等方案。

识别 fill() 在初始化对象数组时的“引用共享”陷阱,关键不是等出错再排查,而是从写法、行为和验证三方面提前判断。下面几个信号一出现,基本就能断定存在共享风险。
看写法:出现 fill(对象字面量或构造调用) 就要警惕
只要 fill() 的参数是引用类型(包括 {}、[]、new Date()、new Map() 等),就必然触发引用复制:
-
Array(3).fill({})→ 三个元素都指向同一个空对象 -
Array(4).fill([])→ 四个元素都指向同一个空数组 -
Array(2).fill(new Set())→ 两个元素共用一个 Set 实例
这种写法看似简洁,实则埋下静默 bug。原始类型(如 0、'a'、null、undefined)无此问题,因为它们按值存储。
看行为:修改一个,其余跟着变
这是最直接的运行时表现。例如:
const arr = Array(3).fill({ name: 'Alice' });
arr[0].age = 25;
console.log(arr[1].age); // 25 —— 不该出现
或者二维场景:
const grid = Array(2).fill(Array(3).fill(0)); grid[0][0] = 99; console.log(grid[1][0]); // 99 —— 明显异常
一旦观察到“改一处、多处同步更新”,几乎可以 100% 确认是引用共享所致。
看内存:用 === 或 Object.is 验证是否同一对象
在开发中加一句简单断言,就能立刻验证:
-
arr[0] === arr[1]返回 true → 共享引用 -
Object.is(arr[0], arr[1])同样返回 true - 对数组项调用
arr[0].constructor.name和arr[1].constructor.name一致,但还不够;必须比地址
在调试器中展开数组,如果所有对象旁都显示 Object {…} (same as #1) 这类提示,也是强信号。
看替代方案是否被绕过
如果代码里出现了这些模式,说明作者可能意识到了问题但没选最优解:
-
Array(5).fill(null).map(() => ({}))——fill(null)只为“填平空位”,本质靠map构造,不如直写Array.from({ length: 5 }, () => ({})) -
Array(3).fill().map(() => [])—— 正确但略冗余,fill()这步纯属占位 - 注释里写着“防止引用共享”却仍用
fill([])→ 逻辑自相矛盾
这类写法往往意味着“知道有问题,但没彻底改掉根源”。

















