组合继承中子类原型不保留父类实例属性,是因为object.create(parent.prototype)仅建立原型链而不执行parent构造函数,避免了new parent()导致的共享实例属性问题;属性通过parent.call(this)继承,方法通过原型链共享,并需手动修复constructor指向child。

组合继承中子类原型对象不保留父类实例属性,是因为它刻意避免了原型链继承的原始做法——不把 Child.prototype 设为 new Parent() 的实例,而是用 Object.create(Parent.prototype) 创建一个干净的原型对象。这个操作切断了父类构造函数执行时产生的实例属性(如 this.name、this.arr)在原型上的挂载路径。
为什么 new Parent() 会带出实例属性?
在原型链继承中,若写 Child.prototype = new Parent(),JavaScript 真实执行的是:
- 调用
Parent构造函数,生成一个全新对象; - 该对象的自有属性(例如
name、colors = ['red'])被直接写入这个新对象; - 这个新对象成为
Child.prototype,所有Child实例共享它的属性和方法。
这就导致引用类型属性被多个子类实例共用,且无法在创建子类实例时向父类传参初始化。
Object.create(Parent.prototype) 做了什么?
这行代码创建的是一个“空壳对象”,其内部 [[Prototype]] 指向 Parent.prototype,但自身不含任何父类构造函数执行产生的实例属性:
- 不执行
Parent构造函数,所以this.name、this.arr等不会被创建; - 新对象只有隐式原型链接,没有自有属性污染;
- 子类实例仍可通过原型链访问
Parent.prototype上的方法(如sayName),但不会意外继承父类实例的私有数据。
属性与方法的职责彻底分离
组合继承通过两步实现清晰分工:
-
属性由构造函数继承承担:在
Child构造函数内调用Parent.call(this, ...),确保每个子类实例拥有独立的name、friends等; -
方法由原型链继承承担:通过
Object.create(Parent.prototype)让所有子类实例共享Parent.prototype上定义的方法,节省内存且支持动态复用。
这种分离让子类原型对象回归本质——只承载可复用的行为,不掺杂状态数据。
constructor 指针为什么要手动修复?
因为 Object.create(Parent.prototype) 创建的对象,其 constructor 属性继承自 Parent.prototype,默认指向 Parent:
- 如果不写
Child.prototype.constructor = Child,新建的child1实例调用child1.constructor会返回Parent,逻辑错乱; - 修复只是语义补全,不影响功能,但对 instanceof 判断、调试、序列化等场景很关键。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











