I’m new to JS and implementing a polymorphic class hierachy. It appears that within the super constructor (when called from a derived constructor), ‘this’ refers to the derived class, not the super class.
So, when the super constructor calls a method that the derived class has overridden, it calls the derived class version not the (original) super class version. This is not the behaviour I wanted, as it means the super constructor behaves differently for the same input parameters when it is called via the derived constructor.
A minimum working example is below:
class A {
constructor(x) {
console.log("A constructor");
this.x = x;
this.foobar();
}
foobar() {
console.log("A foobar");
}
}
class B extends A {
constructor(x, y) {
console.log("B constructor");
super(x);
this.y = y;
}
foobar() {
console.log("B foobar");
}
}
let a = new A(123);
let b = new B(123, 456);
console.log
output is:
A constructor
A foobar
B constructor
A constructor
B foobar (I would have expected this to be 'A foobar')
Have I done something wrong, and if not is there a fairly straightforward way to ensure the original (super) method is always called by the super constructor?
Many thanks in advance for any advice.
PS: I have found similar question here:
How can I prevent calling a super function from the derived class function?
The answer given is to get the super constructor to check whether the instance is of the derived type and change behaviour accordingly. This seems cumbersome, but I could go with that if no-one can suggest a better solution.
2
Answers
To ensure the original method runs in the
super
constructor, call it directly usingA.prototype.foobar.call(this)
. This avoids calling the overridden method in derived classes.In the original code, the issue was that calling this.foobar() in A’s constructor invoked the foobar method of the derived class (B), if B overrode it. This happened because this in the A constructor refers to the instance being created, which is actually an instance of B.
To resolve this, you directly call A.prototype.foobar.call(this); within A’s constructor instead of this.foobar(). This approach ensures that A’s original foobar method is called, even if B or any other subclass overrides foobar.
So, instead of relying on this to find the method, we specifically tell JavaScript to use A’s version of foobar.