tl;dr: Every class field (static or not) is internally wrapped in a method which gets invoked with the corresponding receiver (class or instance) at some point.
So, I'm not sure on some of those details *, but basically this happens:
For every field with an initializer (static or not), a function/method is created, with the initializer as its body. So this
static foo = () => this.v;
becomes something like this internally
function () { () => this.v }
That's in the proposal in step 28, which eventually leads to ClassFieldDefinitionEvaluation
in this spec. The method is created in step 3.e.
The static fields (which are methods now) are then taken and called with the class object itself as receiver (i.e. the this
value inside that intermediate method is set to the class object). This happens in step 34.a, which leads to DefineField
in this spec. Finally the return value (in your case the arrow function) is used as value for the actual property.
Expressed as code, this is roughly what happens:
class Foo {}
Foo.v = function() { return 123; }.call(Foo);
Foo.bar = function() { return () => this.v; }.call(Foo);
*: I'm not quite clear how the intermediate method returns the value, but there is probably something that says that the last expression of the function body is returned or something.
FunctionCreate(Method, formalParameterList, Initializer, lex, true, privateScope).
hasPrivateScope
andStrict
swapped. – SelfconsequenceDefineField
: tc39.es/proposal-class-fields/#sec-define-field (step 5.a) – MortonmortuaryFunctionCreate(Method, formalParameterList, Initializer, lex, true, privateScope)
but should beFunctionCreate(Method, formalParameterList, Initializer, lex, privateScope, true)
– SelfconsequenceDefineField
doesn't seem to be used for static fields though? Need to do more digging... – Mortonmortuary