I have a code like the following:
class ClickModule {
constructor() {
this.handleClick = this.handleClick.bind(this);
}
handleClick = (evt) => {}
}
class ImageModule extends ClickModule {
handleClick(evt) {
//some logic that never gets called
}
}
handleClick is a function used as a callback. I know you cannot bind an arrow function, but as it is being overridden as a class method, why is it not working?
The fix was to declare the initial handleClick as
handleClick(evt) {}
But I don't understand quite well what was producing that the handleClick in ImageModule was never called.
Thanks
I tested it on this codePen https://codepen.io/mpfrancog/pen/rNZREdx
The handleClick
on ImageModule
isn't being used at all, because ClickModule
's class property (not method) is assigned to the instance at construction time, so it takes precedence over the handleClick
on the prototype the instance gets from ImageModule.prototype
.
Here's what happens when you do new ImageModule
:
The (automatically-generated) ImageModule
constructor is called.
It calls ClickModule
's constructor.
Just before ClickModule
's constructor is called, an instance is created using ImageModule.prototype
as its prototype. ImageModule.prototype
has handleClick
from ImageModule
, so for this brief moment, the instance would inherit that method. But...
The code in ClickModule
's constructor is called.
handleClick = (evt) => {}
When the class was built, that code was put in the constructor as though the constructor started with this:
Object.defineProperty(this, "handleClick", {
"value": (evt) => {},
"writable": true,
"enumerable": true,
"configurable": true
});
That is, it puts the property on the instance (replacing any property that was there, but there wasn't in this case), so the property the instance inherits from its prototype will not be used.bind
call, using the instance (not prototype) property and then writing to it. The bind
call doesn't have any effect (in this case), since it doesn't bind any arguments and attempts to bind the this
value that the arrow function already closes over.So ImageModule
's handleClick
isn't used at all.
If you want to have a method that subclasses can override, define a method, not a class property:
class ClickModule {
constructor() {
this.handleClick = this.handleClick.bind(this);
}
handleClick(evt) {
// ...presumably some code here...
}
}
class ImageModule extends ClickModule {
handleClick(evt) {
// ...some logic that now _will_ get called...
}
}
That way, the bind
call in ClickModule
is working with the handleClick
on the instance's prototype, which is the one from ImageModule
.