JavaScript继承模式演进的核心是解决属性独立与方法复用两大问题:原型链继承共享引用类型;借用构造函数无法复用方法;组合继承重复调用父构造;寄生组合继承优化为单次调用;ES6 class是语法糖,底层仍基于原型链。

JavaScript 继承模式的演进,本质是围绕两个核心问题不断优化:一是如何让实例拥有独立的属性(尤其是引用类型),二是如何让方法能被复用、不重复创建。早期方案各自只解决一半,后来逐步融合、精简,最终走向更干净、高效、语义清晰的实现方式。
原型链继承:最原始但有硬伤
直接把子类的 prototype 指向父类的一个实例,比如 Child.prototype = new Parent()。这样子类实例就能顺着原型链访问父类原型上的方法,也“看起来”继承了父类构造函数里的属性。
- 问题很明显:父类中定义的引用类型(如
this.arr = [1, 2])会被所有子类实例共享 - 创建
child1和child2后,改一个的数组,另一个也跟着变 - 子类实例化时无法给父类构造函数传参
借用构造函数(call/apply):解决属性隔离,丢了方法复用
在子类构造函数里用 Parent.call(this, ...args),把父类构造逻辑执行一遍,绑定到当前子类实例上。
- 每个实例都有自己的
name、arr等,互不影响 ✅ - 支持向父类传参 ✅
- 但父类原型上的方法(比如
say())完全没被继承 ❌ - 如果在构造函数里定义方法,每次新建实例都会重新创建函数,浪费内存 ❌
组合继承:ES5 时代的主流方案
把上面两种方式拼起来:子类构造函数里调一次 Parent.call() 处理实例属性;再让 Child.prototype = new Parent() 处理原型方法。
立即学习“Java免费学习笔记(深入)”;
- 既保证属性独立,又实现方法复用,语义清楚,兼容性好 ✅
- 但父类构造函数被调用了两次:一次在
new Parent()设原型时,一次在子类构造里call()时 - 第一次调用只是为设原型,却无谓地初始化了
this.name、this.arr等属性,属于冗余操作
寄生组合继承:目前最推荐的 ES5 方案
它修正了组合继承的“重复调用”问题,核心是用 Object.create(Parent.prototype) 创建一个干净的原型对象,不执行父类构造函数。
- 只调用一次父类构造函数(仅在子类构造中
call),避免冗余初始化 ✅ - 子类原型准确指向父类原型,
instanceof和isPrototypeOf正常工作 ✅ - 属性独立 + 方法复用全部满足,结构清晰,性能更好 ✅
- 社区普遍认为这是 ES5 下引用类型继承的理想范式
ES6 class:语法糖,底层仍是原型链
class 和 extends 让写法接近传统 OOP,但不是新模型。编译后还是基于 __proto__ 和 prototype 的那一套。
- 写起来简洁:
class Child extends Parent一行搞定 - 自动处理构造函数调用、原型链接、
super()约束等细节 - 私有字段(
#field)、静态块(static {})增强了封装能力 - 但理解它,仍需懂原型链——否则遇到
this绑定、方法丢失等问题时容易懵


















