组合继承通过构造函数调用实现属性独立、原型链设置实现方法复用,再修复constructor并验证instanceof与hasOwnProperty,兼顾可靠性、可读性与兼容性。

组合继承能同时解决属性独立和方法复用两个核心问题,关键不在“完美”,而在于明确每一步的作用和边界——它不是零缺陷方案,但足够可靠、易懂、兼容性好。
构造函数调用:确保每个实例拥有自己的属性
在子类构造函数内部,用 Parent.call(this, ...args) 把父类初始化逻辑执行在当前子实例上。这会让 this.name、this.colors 等属性直接挂载到实例本身,而不是共享在原型上。
- 引用类型(如数组、对象)不会被多个实例意外共用
- 支持向父类传参,比如
new Child('Alice', 10)中的'Alice'可传给Parent构造函数 - 避免把初始化逻辑写在原型上——原型只放方法,不放状态
原型链设置:让所有实例共享方法,不重复创建
用 Child.prototype = Object.create(Parent.prototype) 建立干净的原型链。比起 new Parent(),Object.create 不会触发父构造函数执行,避免副作用和冗余属性污染子原型。
-
Object.create(Parent.prototype)创建一个空对象,其[[Prototype]]指向Parent.prototype - 子实例调用
sayName()时,会顺着child → Child.prototype → Parent.prototype查找 - 父类方法只定义一次,内存友好,且可被所有子实例复用
constructor 修复:保持实例与构造器的语义一致
设置原型后,Child.prototype.constructor 默认指向 Parent。必须手动改回 Child,否则 instance.constructor === Parent 会误导调试或序列化逻辑。
- 补上
Child.prototype.constructor = Child这一行 - 也可用
Object.defineProperty设置为不可枚举,更贴近原生行为 - ES6 class 的
extends会自动处理这点,手写时不能跳过
验证是否生效:用 instanceof 和属性访问双重确认
创建实例后,检查两件事:一是能否访问父类方法(走原型链),二是实例自有属性是否隔离。
-
child1 instanceof Child和child1 instanceof Parent都应返回true -
child1.hasOwnProperty('name')应为true,说明属性在实例上 -
child1.sayName能调用,但child1.sayName === child2.sayName为true,说明方法共享

















