组合继承是原型式继承与构造函数继承的结合,即在子类构造函数中用parent.call(this, ...args)继承实例属性,在子类原型上用object.create(parent.prototype)继承方法并修正constructor指向。

原型式继承与构造函数继承结合,本质就是组合继承——用构造函数继承保证每个实例拥有独立的属性(尤其支持传参和避免引用类型共享),再用原型式继承复用父类方法,兼顾隔离性与复用性。
构造函数继承:负责实例属性初始化
在子类构造函数中,用 Parent.call(this, ...args) 调用父类构造函数,把父类定义在 this 上的属性(如 name、habits)复制到当前子类实例上。
- 每个子类实例都拥有自己的一份属性副本,互不影响
- 支持向父类传参,比如
Dog.call(this, '旺财', ['eat', 'bark']) - 但无法访问父类原型上的方法(如
sayName()),纯靠它不够
原型式继承:负责方法复用
让子类的 prototype 指向父类的一个实例(常用 Object.create(Parent.prototype)),使所有子类实例能通过原型链访问父类原型上的方法。
- 方法被共享,节省内存,避免重复创建函数
- 必须手动修复
constructor,否则new Child().constructor会指向Parent - 不能直接用
Sub.prototype = Parent.prototype,否则修改子类原型会影响父类
组合起来的标准写法
把上面两步串起来,就是组合继承的完整流程:
- 子类构造函数内调用
Parent.call(this, ...)—— 拿属性 - 子类原型设为
Object.create(Parent.prototype)—— 接方法 - 补上
Child.prototype.constructor = Child—— 修正构造器指向 - 再往
Child.prototype上添加子类独有方法
为什么不用 new Parent() 设原型?
虽然早期常用 Child.prototype = new Parent(),但它会执行一次父类构造函数,可能带来副作用(比如初始化了不该初始化的引用属性)。现代推荐用 Object.create(Parent.prototype),它只建立原型链连接,不触发父类构造逻辑,更干净安全。











