寄生组合式继承是目前 JavaScript 中最接近“完美”的继承方案,它通过 Object.create(SuperType.prototype) 避免父类构造函数重复执行,保留 SuperType.call(this) 实现属性私有化,并借助 inheritPrototype 等封装函数桥接原型,达成属性隔离与方法复用的统一。

寄生组合式继承是目前 JavaScript 中最接近“完美”的继承方案,它解决了组合继承中父类构造函数被调用两次的核心缺陷,同时保留了属性私有化和方法复用的全部优势。识别它,关键不是看有没有“继承”字样,而是盯住三点:是否绕开了 new 父类() 来设置子类原型、是否仍用 父类.call(this) 初始化实例属性、以及是否通过一个中间封装函数来桥接原型。
看子类原型是否由“非构造函数调用”方式创建
寄生组合式继承绝不直接写 SubType.prototype = new SuperType()。它会用一个辅助函数(如 inheritPrototype)先基于 SuperType.prototype 创建副本,这个副本本身不是 SuperType 的实例,不触发构造函数执行。
- 典型操作是:
Object.create(SuperType.prototype),或手动实现的等效逻辑(如临时构造函数 + 原型赋值) - 结果是:子类原型链顶端指向
SuperType.prototype,但子类原型对象上没有父类构造函数里初始化的实例属性(比如this.colors = [...]) - 如果你看到
SubType.prototype = { __proto__: SuperType.prototype }或类似语义的代码,基本就是它
看子类构造函数内是否仍调用父类.call(this)
和组合继承一样,它依然在子类构造函数第一行使用 SuperType.call(this, ...) 或 SuperType.apply(this, arguments)。
- 目的没变:确保每个子类实例拥有自己独立的引用类型属性(如数组、对象),避免共享
- 区别在于:这次父类构造函数只执行一次——仅在实例化时,不再为设置原型而额外执行
- 若构造函数里完全没调用父类,那可能是原型链继承或寄生式继承,不是寄生组合式
看是否存在一个专门用于“原型桥接”的封装函数
这是最显著的视觉线索。寄生组合式继承几乎总是伴随一个独立的、职责单一的工具函数,名字常含 inheritPrototype、extend 或 createProto 等关键词。
- 该函数接收两个参数:子类构造函数和父类构造函数
- 内部核心逻辑是:用
Object.create(superType.prototype)得到干净原型对象 → 补上.constructor指向子类 → 赋给subType.prototype - 如果没有这个函数,而是把所有逻辑揉进子类定义里,也可能是,但可读性差,不够典型
验证效果:一次调用,两全其美
运行后可观察两个现象,同时成立才说明是寄生组合式继承:
- 修改某个实例的引用属性(如
instance1.colors.push("black")),其他实例不受影响 → 属性隔离成功(靠call) - 所有实例都能访问同一个父类原型方法(如
instance1.sayName() === instance2.sayName()返回true)→ 方法复用成功(靠干净原型链) - 调试时检查
SubType.prototype,里面找不到父类构造函数中定义的实例属性(如没有colors数组),只有方法和constructor→ 确认未重复执行父构造函数

















