Reputation: 3237
TLDR; How to directly call setter of an object's parent class without invoking the child's setter outside of both the parent and child class?
I know that if the solution exists, it may be very hacky/magic-like, but I don't mind. Here's the scenario:
Parent
is class from a 3rd party library so I can't change this code at all.Child
is a class from my codebase, but I'd like to keep the magic code outside of it, as the Prop
class may be use with different "Child
" classes.Prop
is the class where the magic code may reside if necessary.I need to access the Parent
's setter of x
via a Child
object without invoking the setter of x
of the Child
.
Is it even possible?
class Parent {
constructor() {
this._x = 255;
}
set x(v) {
console.log("Calling Parent setter");
this._x = v;
}
get x() {
console.log("Calling Parent getter");
return this._x;
}
}
class Child extends Parent {
constructor() {
super();
this.prop = new Prop(this);
}
set x(v) {
console.log("AVOID! Calling Child setter");
super.x = v;
// Shennanigans I don't want to run
}
get x() {
console.log("Calling Child getter");
return super.x;
}
}
class Prop {
constructor(child) {
this.child = child;
}
setX() {
const parent = this.child; // Not sure what to do here.
const old = parent.x;
parent.x = 0;
console.log(`parent.x changed from ${old} to ${parent.x}`);
}
}
const child = new Child();
child.prop.setX();
Upvotes: 4
Views: 1514
Reputation: 664876
Reflect.set
is here to your rescue! It does allow to pass the receiver separately:
setX() {
Reflect.set(Parent.prototype, "x", 0, this.child); // invokes the Parent.protype.x setter
}
Alternatives would be Object.getOwnPropertyDescriptor(Parent.prototype, "x").set.call(this.child, 0)
or just this.child._x = 0
(if you don't need to run the setter code).
So while it is possible, I would recommend to reconsider your design. Maybe inheritance is the wrong approach here, and you should use composition instead of extends Parent
:
class Child {
constructor() {
this.val = new Parent();
}
set x(v) {
… // Shenanigans
this.val.x = v;
}
get x() {
return this.val.x;
}
// (without the Prop helper class for simplicity)
setX(v) {
// without shenanigans
this.val.x = v;
}
}
Upvotes: 7