Javascript 深度继承和超级构造函数
Javascript deep inheritance and the super constructor
我想弄清楚 super 在 JavaScript 中的真正作用。
我有一个想法,但我不确定它是否准确,所以我需要一些帮助。
class A {
}
class B extends A {
constructor() {
super();
}
}
class C extends B {
constructor() {
super();
}
}
new C
在上面的代码中,'new' 运算符创建了一个对象并将其链接到构造函数 C 的原型,构造函数 C 的隐藏 属性 'thisArg' 现在指向新创建的对象
+---------------------+
| function object |
+---------------------+
| - code |
+---------------------+
| - outerScope |
+---------------------+
| - thisArg |
+---------------------+
| - [[Prototype]] |
+---------------------+
| + prototype |
+---------------------+
| + length |
+---------------------+
| + name |
+---------------------+
N.B。隐藏的 属性 thisArg 可以在每次函数调用时更改,隐式(使用访问运算符“.”和“[]”)、显式(使用 .call、.apply、.bind 方法)或使用 'new'运算符
词法环境的 'this' 引用将指向任何隐藏的函数 属性 thisArg 指向
回到流程。 构造函数 C 被执行,然后 super 将新创建的对象传递给构造函数 B,构造函数 B 的隐藏 属性 thisArg 现在指向新创建的对象
同样的情况发生在构造函数 B 上,它被执行并且 super 将新创建的对象传递给构造开始的 A 构造函数
当 A 完成构造后,它将对象向下传递给 B
然后 B 向结构中添加更多的插槽并向下传递给 C
最后C结束构造,returns构造出对象
所以基本上,新创建的对象首先从一个构造函数冒泡到另一个构造函数,然后滴落下来?
这不是 class
的工作方式。它的构造部分与旧的基于 function
的设置接近正确,但 class
在这方面的工作方式略有不同。
当您执行 new C
时,在调用 A
构造函数之前不会创建对象。这是发生了什么:
new
调用 C
的 [[Construct]] 内部方法并将 new.target
设置为 C
。
- 运行
super()
之前 C
中的任何代码。 this
此时无法访问。
C
的代码调用 B
的 [[Construct]](通过 super()
),new.target
仍设置为 C
。
B
中 super()
之前的任何代码运行。 this
仍然可以访问。
B
调用 A
的 [[Construct]](通过 super()
),new.target
仍设置为 C
。
- 由于
A
是基础构造函数,A
的 [[Construct]] 创建对象,从 prototype
属性 的 new.target
(即 C
)。
A
构造函数中的任何代码都可以运行,并且可以访问 this
。
B
中 super()
运行后的任何代码(并且可以访问 this
)。
super()
运行后 C
中的任何代码(并且可以访问 this
)。
A
创建的对象是 new
表达式的结果。
(为了清楚起见,我跳过了上面的一些次要细节。)
这就是 class
构造确保新对象按顺序 从基本构造函数 (A
) 到第一个派生构造函数 初始化的方式(B
) 最后是 new
目标 (C
)。这样,A
首先可以访问新对象,然后是 B
,然后是 C
。
以上规范 link 中有更多内容。
我想弄清楚 super 在 JavaScript 中的真正作用。 我有一个想法,但我不确定它是否准确,所以我需要一些帮助。
class A {
}
class B extends A {
constructor() {
super();
}
}
class C extends B {
constructor() {
super();
}
}
new C
在上面的代码中,'new' 运算符创建了一个对象并将其链接到构造函数 C 的原型,构造函数 C 的隐藏 属性 'thisArg' 现在指向新创建的对象
+---------------------+
| function object |
+---------------------+
| - code |
+---------------------+
| - outerScope |
+---------------------+
| - thisArg |
+---------------------+
| - [[Prototype]] |
+---------------------+
| + prototype |
+---------------------+
| + length |
+---------------------+
| + name |
+---------------------+
N.B。隐藏的 属性 thisArg 可以在每次函数调用时更改,隐式(使用访问运算符“.”和“[]”)、显式(使用 .call、.apply、.bind 方法)或使用 'new'运算符
词法环境的 'this' 引用将指向任何隐藏的函数 属性 thisArg 指向
回到流程。 构造函数 C 被执行,然后 super 将新创建的对象传递给构造函数 B,构造函数 B 的隐藏 属性 thisArg 现在指向新创建的对象
同样的情况发生在构造函数 B 上,它被执行并且 super 将新创建的对象传递给构造开始的 A 构造函数
当 A 完成构造后,它将对象向下传递给 B
然后 B 向结构中添加更多的插槽并向下传递给 C
最后C结束构造,returns构造出对象
所以基本上,新创建的对象首先从一个构造函数冒泡到另一个构造函数,然后滴落下来?
这不是 class
的工作方式。它的构造部分与旧的基于 function
的设置接近正确,但 class
在这方面的工作方式略有不同。
当您执行 new C
时,在调用 A
构造函数之前不会创建对象。这是发生了什么:
new
调用C
的 [[Construct]] 内部方法并将new.target
设置为C
。- 运行
super()
之前C
中的任何代码。this
此时无法访问。 C
的代码调用B
的 [[Construct]](通过super()
),new.target
仍设置为C
。B
中super()
之前的任何代码运行。this
仍然可以访问。B
调用A
的 [[Construct]](通过super()
),new.target
仍设置为C
。- 由于
A
是基础构造函数,A
的 [[Construct]] 创建对象,从prototype
属性 的new.target
(即C
)。 A
构造函数中的任何代码都可以运行,并且可以访问this
。
- 由于
B
中super()
运行后的任何代码(并且可以访问this
)。
super()
运行后C
中的任何代码(并且可以访问this
)。
- 运行
A
创建的对象是new
表达式的结果。
(为了清楚起见,我跳过了上面的一些次要细节。)
这就是 class
构造确保新对象按顺序 从基本构造函数 (A
) 到第一个派生构造函数 初始化的方式(B
) 最后是 new
目标 (C
)。这样,A
首先可以访问新对象,然后是 B
,然后是 C
。
以上规范 link 中有更多内容。