Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to directly call setter of an object's parent class?

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();
like image 478
sjaustirni Avatar asked Sep 13 '25 04:09

sjaustirni


1 Answers

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;
  }
}
like image 164
Bergi Avatar answered Sep 14 '25 18:09

Bergi