Array.prototype.fill()填充对象时所有元素引用同一实例,因对象按引用传递;基本类型安全,对象类型会共享内存导致副作用;应使用Array.from({length:3},()=>({}))等方案创建独立实例。

直接用 Array.prototype.fill() 填充对象(如空对象 {}、数组 [] 或正则表达式 /./)时,所有数组元素会**引用同一个对象实例**——这不是“复制”,而是“重复引用”。这是典型的引用陷阱,容易导致意料之外的副作用。
为什么 fill() 会产生共享内存?
fill(value) 只把传入的 value 这个**值本身**(注意:对象类型传的是引用地址)写进每个位置。JavaScript 中对象是按引用传递的,所以:
- 若
value是基本类型(0、'a'、true),每次写入的是独立副本,安全; - 若
value是对象({}、[]、new Date()等),所有索引指向同一块堆内存,修改任一元素都会影响全部。
典型错误示例与后果
比如想创建 3 个独立空对象组成的数组:
const arr = new Array(3).fill({});<br>arr[0].name = 'Alice';<br>console.log(arr); // [{name: 'Alice'}, {name: 'Alice'}, {name: 'Alice'}] ❌再如初始化二维数组时误用:
const matrix = new Array(2).fill(new Array(3).fill(0));<br>matrix[0][0] = 99;<br>console.log(matrix[1][0]); // 99 —— 第二行也被改了 ❌
安全替代方案(不共享引用)
要生成**独立对象实例**,必须在每次赋值时调用构造逻辑,不能复用同一引用。常用方法:
-
Array.from + 映射函数:最推荐,语义清晰且可控
Array.from({ length: 3 }, () => ({}))✅ -
Array(n).keys().map():利用索引驱动新建
[...Array(3).keys()].map(() => ([]))✅ -
for 循环手动 push:简单直白,适合复杂初始化逻辑
const arr = []; for (let i = 0; i ✅ -
避免 fill 配合对象字面量:永远不要写
fill({})、fill([])、fill(/a/g)
特殊情况:需要共享引用时怎么办?
极少数场景确实需共享(如共用一个配置对象、事件总线实例),那就明确意图,用注释说明:
// ⚠️ 故意共享同一 config 实例,所有项共用状态<br>const configs = new Array(5).fill(defaultConfig);
但这类设计需谨慎评估可维护性,通常更建议通过闭包或工厂函数控制共享粒度。










