fill() 不会深拷贝,对引用类型只复制同一内存地址,导致多个数组元素共享同一对象;正确做法是用 Array.from() 或循环每次生成新实例。
array.prototype.fill() 本身不会创建“共享内存”,但它在填充**引用类型值(如对象、数组)时,会把同一个引用复制到每个位置——这正是“共享引用”而非“共享内存”的源头。所谓“bug”,其实是误以为 fill 会深拷贝,结果多个数组元素指向同一对象,修改任一元素都会影响其他。
为什么 fill(obj) 会导致意外的联动修改?
因为 fill() 只做浅赋值:传入一个对象字面量或变量,它把该对象的内存地址复制 N 次,填进数组各索引。所有项共用同一份数据。
例如:
const arr = new Array(3).fill({ x: 0 });
arr[0].x = 99;
console.log(arr.map(o => o.x)); // [99, 99, 99] ← 全变了
正确做法:用 Array.from() 或循环生成独立对象
核心思路是:**每次填充都执行一次构造逻辑,确保每个元素是全新实例。**
- 推荐 Array.from() + 箭头函数:简洁且语义清晰
// ✅ 每个对象都是独立的
const arr = Array.from({ length: 3 }, () => ({ x: 0 }));
arr[0].x = 99;
console.log(arr.map(o => o.x)); // [99, 0, 0]
- 用 map() 配合空数组(需先创建稀疏数组再映射)
const arr = [...new Array(3)].map(() => ({ x: 0 }));
- 显式 for 循环:最直观,适合复杂初始化逻辑
const arr = [];
for (let i = 0; i < 3; i++) {
arr.push({ x: 0 });
}
特殊情况:需要部分共享?明确控制引用关系
有时你确实希望某些字段共享(如配置对象),但主体结构独立。这时应主动拆分设计:
- 把共享数据抽成常量,仅在对象中存引用或 ID
- 使用工厂函数封装创建逻辑,内部决定哪些复用、哪些新建
const sharedConfig = { timeout: 5000 };
const arr = Array.from({ length: 3 }, () => ({
id: Math.random(),
config: sharedConfig, // 显式共享配置
data: [] // 独立数据容器
}));
补充提醒:fill() 不是敌人,只是工具
对原始值(number/string/boolean/null/undefined)调用 fill() 完全安全,因为它们按值传递;对函数、正则等也是独立副本(引擎保证)。陷阱只出现在你主动传入可变引用类型时。
真正要规避的不是 fill,而是「假设 fill 会克隆对象」这个误解。

















