寄生组合式继承通过清晰的原型链结构让javascript引擎静态优化方法调用,关键在于方法统一挂载父类原型、避免object.assign破坏链稳定性、冻结原型、禁止构造函数内定义方法,并优先使用class extends语法以触发引擎深度优化。

寄生组合式继承本身不靠运行时修补提性能,而是结构清晰、语义明确,让现代 JavaScript 引擎(如 V8)能静态识别并深度优化方法调用。优化关键不在“怎么写继承”,而在于“怎么组织原型链和方法定义”,让引擎自动启用 IC 缓存、内联与去虚拟化。
确保方法全部挂在父类原型上,不拷贝、不覆盖
子类原型必须通过 Object.create(Parent.prototype) 或中转函数方式继承,不能用 Object.assign(Child.prototype, Parent.prototype)。后者会把父类原型方法平铺到子类原型,破坏原型链的稳定性,导致引擎无法确认方法位置,IC 缓存失效,也无法内联。
- 正确:Parent.prototype.sayName = function() { ... }; Child.prototype 继承自它,不添加同名方法
- 错误:在 Child.prototype 上重新定义 sayName,或用 Object.assign 复制,造成方法重复、不可预测
- 额外建议:对 Parent.prototype 调用 Object.freeze()(尤其在 strict 模式下),向引擎明确声明“这些方法不会被改写”,进一步支持去虚拟化
避免在构造函数中动态挂载方法
方法应始终存在于原型链上,而非在子类构造函数里给 this 添加函数。否则每个实例都生成独立函数对象,既浪费内存,又使引擎无法复用隐藏类和内联路径。
- 不要写:
this.sayAge = function() { console.log(this.age); }; - 要写:
Child.prototype.sayAge = function() { console.log(this.age); }; - 这样所有 Child 实例共享同一个 sayAge 函数,引擎可稳定命中 IC,并在热点代码中直接跳转到 Parent.prototype.sayName
配合 class 语法显式声明继承关系
虽然寄生组合式继承可手写,但 class Child extends Parent 是更优选择。它不是语法糖,而是向引擎发出强信号:
- extends Parent 让引擎在解析阶段就预构建完整原型链拓扑
- constructor 中必须 super(),强制 this 初始化顺序,便于隐藏类推导
- V8 等引擎对 super() 调用有专用优化路径,比手动 Parent.call(this) 更高效
- Babel/TypeScript 在降级时默认输出寄生组合式逻辑,并自动补全 Object.setPrototypeOf 等辅助优化(在支持环境)
控制父类构造函数副作用,减少干扰
方法调用性能还受构造函数影响:若 Parent 构造函数执行耗时操作(如创建 DOM、发起请求模拟、深克隆),会拖慢实例化,间接影响后续方法调用的启动速度。
- 将重逻辑抽离为独立初始化方法(如 initUI()、loadData()),由子类按需调用
- 避免在继承链深层重复调用同一父构造函数(例如 A ← B ← C,C 不应再显式 call A)
- 用 Reflect.construct 替代 Parent.apply,更好支持 new.target 和 Symbol.species,提升语义健壮性











