In your first example, the creation and initialization of the public instance field named defaultValue
in Child
occurs after the creation and initialization of the public instance field named value
in Parent
.
So: even though the this
value in the initializer of the public instance field named value
in Parent
will point to the instance of Child
under construction, the child-local public instance field named defaultValue
does not yet exist, and so the prototype chain is followed up to the property named defaultValue
on the instance of Parent
, yielding 1
.
In your latter example, you have getter functions named defaultValue
.
Getter functions specified in this way, even though their API deliberately looks like that of public instance fields, will end-up as functions on the [[Prototype]]
of any instance under construction.
The [[Prototype]]
objects of instances are created at the time of class declaration (ie. always before anything triggered by instance construction), as the .prototype
property of the class (or constructor function); references to these objects are then copied to the [[Prototype]]
of any instance under construction as the first step in object construction (think Object.create(class.prototype))
.
And so this.defaultValue
from the Parent
public instance initializer for value
resolves to the getter on the [[Prototype]]
of the instance of Child
under construction, which is a function that returns 2
.