I’m trying to figure out how super really works in JavaScript.
I have an idea but I’m not sure of it’s exactitude so I need some help.
class A {
}
class B extends A {
constructor() {
super();
}
}
class C extends B {
constructor() {
super();
}
}
new C
In the above code the ‘new’ operator creates an object and links it to the constructor C’s prototype, constructor C’s hidden property ‘thisArg’ now points to the newly created object
+---------------------+
| function object |
+---------------------+
| - code |
+---------------------+
| - outerScope |
+---------------------+
| - thisArg |
+---------------------+
| - [[Prototype]] |
+---------------------+
| + prototype |
+---------------------+
| + length |
+---------------------+
| + name |
+---------------------+
N.B. The hidden property ‘thisArg’ can be altered at each function call, implicitly (with access operators ‘.’ and ‘[]’), explicitly (with .call, .apply, .bind methods) or with the ‘new’ operator
Lexical environment’s ‘this’ reference will then point to whatever functions hidden property ‘thisArg’ is pointing at
Back to the process. The constructor C gets executed then the super passes up the newly created object to the B constructor, constructor B’s hidden property ‘thisArg’ now points to the newly created object
same happens with the constructor B, it gets executed and the super passes up the newly created object to the A constructor where the construction starts
When A finishes the construction it passes the object down to B
Then B adds more slots to the structure and passes down to C
Finally C ends the construction and returns the constructed object
So basically, the newly created object first bubbles up from constructor to constructor and then trickles down?
>Solution :
That’s not how it works with class. The construction parts of it would be close to correct with the old function-based setup, but class works slightly differently in this regard.
When you do new C, the object isn’t created until the A constructor is called. Here’s what happens:
newcallsC‘s [[Construct]] internal method withnew.targetset toC.- Any code in
Cprior tosuper()runs.thisis inaccessible at this point. C‘s code callsB‘s [[Construct]] (viasuper()) withnew.targetstill set toC.- Any code in
Bprior tosuper()runs.thisis still in accessible. BcallsA‘s [[Construct]] (viasuper()) withnew.targetstill set toC.- Since
Ais the base constructor,A‘s [[Construct]] creates the object, setting its prototype from theprototypeproperty ofnew.target(which isC). - Any code in the
Aconstructor runs, and has access tothis.
- Since
- Any code in
Baftersuper()runs (and has access tothis).
- Any code in
- Any code in
Caftersuper()runs (and has access tothis).
- Any code in
- The object created by
Ais the result of thenewexpression.
(I’m skipping over some minor details above for clarity.)
This is how the class construct ensures that the new object is initialized in order from the base constructor (A) to the first derived constructor (B) and the finally the new target (C). That way, A has access to the new object first, followed by B, followed by C.
More in in the specification link above.