组合继承是javascript最常用继承模式,通过new父类()实现方法复用、call(this)实现属性私有化,但父类构造函数会被调用两次。
组合继承是 javascript 中最常用、也最推荐的继承模式,它通过两次调用父类构造函数来分别解决属性私有化和方法复用两个核心问题。识别它,关键看代码中是否同时存在“new 父类()”和“父类.call(this, ...)”这两处典型操作。
看子类原型是否由 new 父类() 构建
这是原型链继承的标志。子类的 prototype 被显式赋值为一个父类实例,目的是让子类实例能沿原型链访问父类原型上的方法。
常见写法:
SubType.prototype = new SuperType();- 或带修复 constructor 的写法:
SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType;
看子类构造函数内部是否调用父类.call(this)
这是构造函数继承的标志。在子类构造函数体内,用 call(或 apply)把父类执行一遍,并把 this 绑定到当前子类实例上,目的是让每个子类实例都拥有自己独立的父类实例属性(比如数组、对象等引用类型)。
常见写法:
SuperType.call(this, name);SuperType.apply(this, arguments);
检查是否同时具备属性隔离与方法共享
组合继承的效果是可验证的:
- 修改某个子类实例的引用类型属性(如
instance.colors.push("black")),不会影响其他实例 —— 说明属性已隔离(靠 call 实现); - 所有子类实例都能调用同一个父类原型方法(如
instance.sayName()),且该方法只在内存中存在一份 —— 说明方法已复用(靠原型链实现)。
注意一个典型缺陷:父类构造函数被调用两次
这是识别组合继承的重要线索,也是它后续被寄生组合继承优化的原因:
- 第一次:在设置
SubType.prototype = new SuperType()时,执行了一次父类构造函数(此时创建的是用于继承的“空壳”实例); - 第二次:在
new SubType()实例化时,子类构造函数内SuperType.call(this)又执行一次。
两次调用会导致父类构造函数中的初始化逻辑(比如给 this.colors = ["red"])被执行两遍,虽不影响功能,但略低效。










