Javascript深度继承和超级构造函数

Sle*_*v7n 3 javascript constructor extends super

我试图弄清楚 super 在 JavaScript 中是如何工作的。我有一个想法,但我不确定它的准确性,所以我需要一些帮助。

class A {

}

class B extends A {
    constructor() {
        super();
    }
}

class C extends B {
    constructor() {
        super();
    }
}

new C
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,“new”运算符创建一个对象并将其链接到构造函数 C 的原型,构造函数 C 的隐藏属性“thisArg”现在指向新创建的对象

+---------------------+
|   function object   |
+---------------------+
| - code              |
+---------------------+
| - outerScope        |
+---------------------+
| - thisArg           |
+---------------------+
| - [[Prototype]]     |
+---------------------+
| + prototype         |
+---------------------+
| + length            |
+---------------------+
| + name              |
+---------------------+
Run Code Online (Sandbox Code Playgroud)

注意:隐藏属性 thisArg 可以在每次函数调用时隐式(使用访问运算符 '.' 和 '[]')、显式(使用 .call、.apply、.bind 方法)或使用 'new' 运算符进行更改

词法环境的“this”引用将指向 thisArg 所指向的任何函数隐藏属性

回到流程。构造函数 C 被执行,然后 super 将新创建的对象传递给 B 构造函数,构造函数 B 的隐藏属性 thisArg 现在指向新创建的对象

构造函数 B 也会发生同样的情况,它被执行,并且 super 将新创建的对象传递给构造开始的构造函数 A

当 A 完成构造后,它将对象传递给 B

然后B向该结构添加更多槽并向下传递给C

最后C结束构造并返回构造的对象

那么基本上,新创建的对象首先从构造函数冒泡到构造函数,然后向下滴落?

T.J*_*der 6

这不是它的工作原理class。它的构造部分与旧的设置接近正确function,但class在这方面的工作方式略有不同。

当您这样做时,在调用构造函数new C之前不会创建该对象。A发生的情况如下:

  1. new调用C[[Construct]]内部方法并将new.target其设置为C
    1. C运行之前的任何代码super()this此时无法访问。
    2. C的代码调用 的B[[Construct]] (via super()),但new.target仍设置为C
      1. B运行之前的任何代码super()this仍然处于可访问状态。
      2. B调用A的 [[Construct]] (通过super()),new.target仍设置为C
        1. 由于A是基本构造函数,A因此 的 [[Construct]] 创建对象,并根据( )prototype的属性设置其原型。new.targetC
        2. 构造函数中的任何代码A都会运行,并且可以访问this.
      3. Bafter中的任何代码super()都会运行(并且可以访问this)。
    3. Cafter中的任何代码super()都会运行(并且可以访问this)。
  2. 创建的对象A是表达式的结果new

(为了清楚起见,我跳过了上面的一些小细节。)

这就是class构造如何确保新对象按照从基本构造函数 ( A) 到第一个派生构造函数 ( B) 和最后的目标new( C) 的顺序进行初始化。这样,A首先可以访问新对象,然后是B,最后是C

更多内容请参见上面的规范链接。