1. Babel
Public Class Fields目前是TC39 Stage 2的特性。
在实际项目中,我们使用了Babel进行转译。
Public Class Fields如果是一个箭头函数,那么这个函数中this
的指向,如下所示。
(可在Babel REPL中试验
class A {
v = this; // instance
static f = () => {
return this; // undefined
}
g = () => {
return this; // instance
}
}
alert(A.f() === undefined); // true
const a = new A;
alert(a.g() === a); // true
alert(a.v === a); // true
对于static字段,this
为undefined
。
对于实例字段,this
指向类的实例。
2. Public Class Fields
(1)ClassDefinitionEvaluation
我们看Public Class Fields规范,
执行过程是从ClassDefinitionEvaluation开始的,
这个函数比较长,我们只截取与public class fields有关的部分,如下,
因此在class
声明的时候,对于那些public class fields进行了求值。
实际调用的是ClassPublicFieldDefinitionEvaluation函数,
该函数最后返回了一个Record。
(2)ClassPublicFieldDefinitionEvaluation
其中[[initializer]]
字段是一个函数,由FunctionCreate创建。
FunctionCreate
是ECMAScript规范中定义的函数。
因此,每一个public class fields对应一个Record
,
这个Record
中有一个[[initializer]]
函数字段,
函数体是产生式PublicFieldDefinition: PropertyName Initializer
中的Initializer
,
函数的求值结果是public class fields的值。
为什么不直接使用产生式中Initializer
对应的值呢,
而是要先把它包裹成一个函数。
这是为了改变public class fields等式右边this
指向。
class A {
v = this; // instance
}
到此为止,class
声明时要做的事情就完成了,
然后我们要看实例化时发生的事情。
(3)[[Construct]]
这个函数描述了进行new
操作时发生的事情,
其中,InitializePublicInstanceFields
表示了对public class fields初始化,
OrdinaryCallEvaluateBody表示了求值class
的constructor
函数。
下面我们看InitializePublicInstanceFields
函数。
(4)InitializePublicInstanceFields
这时拿到ClassPublicFieldDefinitionEvaluation
返回的Record
,
获取它的[[initializer]]
函数字段,然后用当前类的实例,调用它,
因此,this
就指向当前类型的实例了。
class A {
v = this;
g = () => {
return this;
}
}
// 声明时,变成了
class A {
v = new Record({
[[initializer]]:function(){
return this;
}
});
g = new Record({
[[initializer]]:function(){
return ()=>{
return this;
}
}
});
}
// new的时候变成了
class A {
v = record.[[initializer]].call(instance);
g = record.[[initializer]].call(instance);
}
因此,public class fields字段中的this
指向类的实例。
参考
Babel REPL - Stage 2
Public Class Fields
ECMAScript® 2017 Language Specification
网友评论