引用类型属性在原型上定义会导致所有实例共享同一份数据,因其存储在原型对象中而非实例自身;应始终在构造函数或constructor中初始化引用类型以确保独立性。

在JavaScript原型继承中,引用类型属性(如数组、对象、函数)会被所有实例共享,这是由原型链的内存机制决定的——它们实际存储在原型对象上,而非每个实例自身。
为什么引用类型会共享
当构造函数的原型上定义了引用类型属性(比如 prototype.items = []),这个数组只在内存中存在一份,所有通过该构造函数创建的实例都通过原型链访问同一个数组。修改其中一个实例的该属性,会影响其他实例。
- 原始值(字符串、数字、布尔)赋值时会复制一份,互不影响
- 引用值(对象、数组等)赋值时只复制地址,指向同一块内存
- 实例自身没有该属性时,读写操作都会落到原型上
典型问题示例
以下代码演示了常见陷阱:
function Person() {}
Person.prototype.hobbies = []; // 引用类型挂载在原型上
const p1 = new Person();
const p2 = new Person();
p1.hobbies.push('reading');
console.log(p2.hobbies); // ['reading'] —— p2 也被影响了
如何避免原型上引用类型共享
核心原则:让每个实例拥有自己独立的引用类型数据,而不是共用原型上的同一份。
立即学习“Java免费学习笔记(深入)”;
-
在构造函数内部初始化:把引用类型赋值写在
function Person() { this.hobbies = []; }中,确保每次新建实例都生成新数组 -
使用 Object.create(null) 或深拷贝防御性初始化:若必须在原型方法中操作引用属性,先检查
this.xxx === undefined再初始化 -
避免在 prototype 上直接声明可变引用类型:如
arr = []、obj = {},这类写法几乎总是错误的
ES6 class 中同样存在该问题
class 本质仍是基于原型的语法糖,下面写法有相同风险:
class Animal {
constructor() {
// ✅ 正确:实例自有
this.skills = [];
}
}
// ❌ 错误:所有实例共享
Animal.prototype.tools = [];
即使使用 class,也要坚持在 constructor 中初始化引用属性,而非放在类体顶层或 prototype 上。


















