super has two unrelated forms.
super(...args) is valid only in a derived constructor. It:
- takes the active constructor's
[[GetPrototypeOf]]()as the parent (so it followsextendseven if you later change it), - calls
Construct(parent, args, newTarget), which passes the originalnew.targetdown so the object ends up with the right prototype, - binds the result as
this(BindThisValue), and - initialises this class's private methods and fields.
Until that happens, this is uninitialised, and reading it throws a ReferenceError. Calling super() twice also throws a ReferenceError. A derived constructor that finishes without calling super() and without returning an object throws too. If you omit the constructor, the default one forwards all arguments to super.
super.x / super[x] is valid in any method, including object-literal methods and static methods. The spec resolves it by taking the method's [[HomeObject]] (the object the method was defined on: Class.prototype, the class itself for statics, or the literal) and doing HomeObject.[[GetPrototypeOf]]() to find the base. The lookup starts there, but getters and methods run with the current this as receiver. That is what makes super.describe() see the instance's data. super.x = v sets on this, using the parent's setter if one exists.
Two implications. super is not a lookup of "the parent class": it's "the prototype of my home object", resolved at call time. And it's tied to where the method was written, not how it's called: extracting const { greet } = obj keeps its super. Arrow functions inherit super and this from the enclosing method; plain function expressions can't use super at all (a SyntaxError).