3

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?

Slev7n
  • 343
  • 3
  • 14
  • 1
    Basically yes. Have you read the `super` section in [How does the "this" keyword work?](/a/3127440/4642212) and the [specification](//tc39.es/ecma262/#sec-super-keyword)? It’s worth pointing out that when doing `new C`, `this` inside the constructors is an instance of `C` (never `A` or `B`), and `this` is only accessible after the last `super` call in the chain. – Sebastian Simon Jan 30 '22 at 12:10
  • 1
    @SebastianSimon - Actually, no. The object isn't created until `A` is called. The above is close(ish) for the old way using `function`, but not `class`. – T.J. Crowder Jan 30 '22 at 12:11
  • @T.J.Crowder That’s what I meant with _“`this` is only accessible after the last `super` call in the chain”_. _If and when_ the constructed object exists, it is an instance of `C`. Hope this is clear enough… – Sebastian Simon Jan 30 '22 at 12:14
  • 1
    @SebastianSimon - Right -- but the explanation above says `this` is created before `C` is called, which is incorrect. – T.J. Crowder Jan 30 '22 at 12:15
  • *"N.B. constructors hidden property 'this' not to be confused with 'this', a member the lexical environment created by a function"* I don't know what you're trying to say there. `this` only has one meaning in JavaScript, there aren't two different ones. – T.J. Crowder Jan 30 '22 at 12:21
  • @T.J.Crowder 'this' within the lexical environment is a mere parameter. It's argument is provided by the function object's 'this', a hidden property, you may call it thisArg – Slev7n Jan 30 '22 at 12:38
  • @Slev7n - This may be a terminology misunderstanding or something. Functions (including constructors) don't have a "hidden 'this' property." [Here's a list of the internal slots of function objects](https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ecmascript-function-objects). `this` is a binding held in (non-arrow) function environment records and module environment records. There is a different thing called `thisArgument`, a parameter of the... – T.J. Crowder Jan 30 '22 at 12:57
  • ...[`[[Call]]` operation](https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ecmascript-function-objects-call-thisargument-argumentslist). But that's not `this`. – T.J. Crowder Jan 30 '22 at 12:57

1 Answers1

6

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.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    FWIW, I go into this stuff in detail in Chapter 4 of my recent book *JavaScript: The New Toys* covering everything in ES2015-ES2020. Links in my profile if you're interested. – T.J. Crowder Jan 30 '22 at 12:30