Slev7n
Slev7n

Reputation: 371

Javascript deep inheritance and the super constructor

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?

Upvotes: 3

Views: 194

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074138

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:

  1. new calls C's [[Construct]] internal method with new.target set to C.
    1. Any code in C prior to super() runs. this is inaccessible at this point.
    2. C's code calls B's [[Construct]] (via super()) with new.target still set to C.
      1. Any code in B prior to super() runs. this is still in accessible.
      2. B calls A's [[Construct]] (via super()) with new.target still set to C.
        1. Since A is the base constructor, A's [[Construct]] creates the object, setting its prototype from the prototype property of new.target (which is C).
        2. Any code in the A constructor runs, and has access to this.
      3. Any code in B after super() runs (and has access to this).
    3. Any code in C after super() runs (and has access to this).
  2. The object created by A is the result of the new expression.

(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.

Upvotes: 6

Related Questions