防止属性共享的关键是:基本类型天然隔离,引用类型必须每次新建;构造函数内须用字面量或构造器初始化数组、对象等引用类型,严禁复用全局变量或原型上的引用值。

构造函数创建实例时,防止属性共享的关键是:**基本类型天然隔离,引用类型必须每次新建**。只要不把数组、对象等引用值直接写在原型上,也不复用外部同一份数据,就能确保每个实例拥有真正独立的属性。
构造函数内初始化引用类型
所有需要独有副本的引用类型(如数组、对象、正则、日期等),必须在构造函数体内用字面量或构造器新建,而不是复用已有变量。
- ✅ 正确:每次 new 都执行 this.items = [] 或 this.config = { mode: 'dark' } —— 每个实例拿到新内存地址
- ❌ 错误:定义全局 const DEFAULT_LIST = [],再写 this.items = DEFAULT_LIST —— 所有实例共用一个数组
- ⚠️ 警惕隐式共享:this.cache = this.cache || new Map() 若原型上有 cache 属性,可能读到共享值;应始终用 new Map() 或 {} 显式新建
别在 prototype 上放引用类型属性
原型上的属性被所有实例共享,若放引用类型,修改会波及全部实例。
- ❌ 危险:Person.prototype.tags = [] → p1.tags.push('admin') 后,p2.tags 也包含 'admin'
- ✅ 安全:把 tags 移入构造函数,或改用 getter 封装:get tags() { return this._tags || (this._tags = []) }
- ? 补充:只读常量可放 prototype,但要用 Object.defineProperty 设置 writable: false,避免被意外改写
验证是否真的独有
不能只看代码逻辑,要动手确认属性归属。
立即学习“Java免费学习笔记(深入)”;
- 用 obj.hasOwnProperty('prop') 或 Object.hasOwn(obj, 'prop') 判断是否为实例自有属性(非继承)
- 比较引用:p1.items === p2.items 应为 false;若为 true,说明共享了
- 修改一个实例的数组后,检查另一个实例对应属性是否未变 —— 这是最直接的验证方式
继承场景下的注意事项
组合继承中,借用父类构造函数(Super.call(this))已解决实例属性共享问题,但仍需注意:
- 子类构造函数里仍要为自己的引用属性新建副本,不能依赖父类传来的引用
- 避免在子类 prototype 上添加可变引用属性,比如 SubType.prototype.queue = new Queue()
- 若需默认配置对象,推荐用工厂函数:this.options = createDefaultOptions(),而非直接赋值对象字面量(除非确保每次调用都新建)


















