javascript中extends构建一条跨构造函数的完整原型继承链,包含child.__proto__指向parent(静态链)和child.prototype.__proto__指向parent.prototype(实例链)两条并行路径。

JavaScript 中 extends 关键字在底层并不“建立两条不同的原型链”,而是**构建一条完整的、跨构造函数的原型继承链**,其中涉及**构造函数原型(Child.prototype)** 和 **构造函数自身(Child)** 两条独立但关联的向上追溯路径——它们分别指向 Parent.prototype 和 Parent,形成“双链并行”的结构。这是理解 ES6 类继承本质的关键。
1. 构造函数自身的原型链(静态链):指向父类构造函数
当使用 class Child extends Parent 时,JavaScript 引擎会设置 Child.__proto__ === Parent。这意味着:
– Child 作为函数对象,其 [[Prototype]](即 __proto__)直接指向 Parent;
– 因此,Child 可以继承 Parent 上的静态方法(如 Parent.method()),也能访问 Parent 自身的属性(如 Parent.name)。
- 这是一条“构造函数到构造函数”的链,用于继承静态成员
- 它与
Function.prototype无关,而是由extends显式设置的 - 例如:
class B extends A {}→B.__proto__ === A为true
2. 实例原型的原型链(实例链):指向父类的原型对象
Child.prototype 的 [[Prototype]] 被设为 Parent.prototype,即:
– Object.getPrototypeOf(Child.prototype) === Parent.prototype;
– 所以通过 new Child() 创建的实例,其 __proto__ 指向 Child.prototype,再往上就到达 Parent.prototype,最终到 Object.prototype。
- 这条链负责方法和属性的动态继承(如
instance.method()) - 它保证子类实例能访问父类原型上的所有可枚举/不可枚举方法
- 注意:
Child.prototype.constructor会被自动修正为Child(而非Parent)
3. 为什么看起来像“两条链”?关键在于两个 __proto__ 层级
每个函数(包括类)都有两个可被追踪的 __proto__ 路径:
-
函数对象自身 的
__proto__→ 指向其父类构造函数(Parent) -
该函数的
prototype对象 的__proto__→ 指向父类的prototype(Parent.prototype)
二者互不干扰,但协同工作:前者让 Child “是” Parent 的一种类型(静态继承),后者让 new Child() “像” new Parent() 一样行为(实例继承)。
4. 底层实现依赖于 Object.setPrototypeOf 和内部初始化
ES6 规范中,extends 的等效逻辑大致如下(简化示意):
- 创建
Child函数,并设Child.__proto__ = Parent - 创建
Child.prototype,并设Object.setPrototypeOf(Child.prototype, Parent.prototype) - 设置
Child.prototype.constructor = Child - 确保
super()调用能正确初始化父类状态(通过内部[[Construct]]和[[OrdinaryCallBindThis]])
这个过程不是“魔法”,而是规范定义的、可预测的原型链接操作,完全基于已有的原型机制,没有引入新链路模型。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











