如何在Javascript中调用祖父母类的setter

时间:2019-03-18 19:26:58

标签: javascript ecmascript-6 es6-class

想象一下,我有3个类ChildParentGrandparent在层次结构中进行了如下连接:

class Grandparent {
  set myField(value) {
    console.log('Grandparent setter');
  }
}

class Parent extends Grandparent {
  set myField(value) {
    console.log('Parent setter');
  }
}

class Child extends Parent {
  set myField(value) {
    //I know how to call Parent's setter of myField:
    //super.myField = value;
    //But how to call Grandparent's setter of myField here?
  }
}

如何在Grandparent类的设置器中调用myField的{​​{1}}的设置器?

我特别对二传手而不是方法感兴趣。同样,最好不要在Child类的Parent中进行更改。

我不知道使用Grandparent是怎么回事,因为它仅引用super类,也无法使用Parent之类的东西,因为我不知道确切地调用什么在原型中。

有人对此案有任何建议吗?

谢谢!

4 个答案:

答案 0 :(得分:7)

  

使用类似Grandparent.prototype.<what?>.call(this, ...)

您在正确的轨道上,可以使用Object.getOwnPropertyDescriptor访问setter方法:

Object.getOwnPropertyDescriptor(Grandparent.prototype, "myField").set.call(this, value);

不过,有一种更简单的方法:将Reflect.set helper与自定义接收者一起使用:

Reflect.set(Grandparent.prototype, "myField", value, this);

这还有一个优势,当Grandparent未定义设置器时,它仍然可以工作。


也就是说,我同意@Dinu的观点,当您需要这样做时,您的类层次结构(或您的一般设计,也许甚至不应该使用类或继承)可能存在问题。

答案 1 :(得分:2)

您可以将Reflect.set()与可选的receiver参数一起使用:

class Grandparent {
  set myField(value) {
    console.log('Grandparent setter');
  }
}

class Parent extends Grandparent {
  set myField(value) {
    console.log('Parent setter');
  }
}

class Child extends Parent {
  set myField(value) {
    Reflect.set(Grandparent.prototype, 'myField', value, this);
  }
}

new Child().myField = 'foo';

如果您没有明确引用Grandparent.prototype,则可以使用Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(this)))代替,这显然不那么可取。不过,您可以创建一个辅助函数:

function getPrototypeOf (target, level = 1) {
  return level > 0 ? getPrototypeOf(Object.getPrototypeOf(target), level - 1) : target;
}

并使用getPrototypeOf(this, 3)代替Grandparent.prototype将原型链递归给祖父母:

function getPrototypeOf (target, level = 1) {
  return level > 0 ? getPrototypeOf(Object.getPrototypeOf(target), level - 1) : target;
}

class Grandparent {
  set myField(value) {
    console.log('Grandparent setter');
  }
}

class Parent extends Grandparent {
  set myField(value) {
    console.log('Parent setter');
  }
}

class Child extends Parent {
  set myField(value) {
    Reflect.set(getPrototypeOf(this, 3), 'myField', value, this);
  }
}

new Child().myField = 'foo';

答案 2 :(得分:1)

您可能会找到一种实现方法,但不应该这样做,因为在使用基于类的OOP时,这样做会破坏基于类的模型。在任何理智的环境中,如果Parent实现setX(),则它希望setX()在其上下文中表现其定义方式。它不会覆盖setX(),因此它可以像以前一样运行。

因此,如果您要问这个问题,那么您要么设计了错误的类层次结构,要么实际上需要基于原型的OOP。

如果您写《父母》,我假设您要获取的是对特定属性的无中介访问。方法是在父/ gradpa上定义一个方法,例如setXClean(),该方法用作celan setter。在这种情况下,您可能希望对其进行保护,并在祖父母身处将其定案。

答案 3 :(得分:0)

在我看来,最简单的方法是在创建myField的Grandparent类中创建另一个唯一的setter或方法。

class Grandparent {
  set myField(value) {
    console.log('Grandparent setter');
  }
  set grandParent_myField(value) { this.myField = value }
}

class Parent extends Grandparent {
  set myField(value) {
    console.log('Parent setter');
  }
}

class Child extends Parent {
  set myField(value) {
    this.grandParent_myField = value
  }
}

另一种选择是将super.myField放在每个设置者的正文中:

class Grandparent {
  constructor() { this._myField = null }
  set myField(value) {
    this._myField = value
  }
}

class Parent extends Grandparent {
  set myField(value) {
    super.myField = value
  }
}

class Child extends Parent {
  set myField(value) {
    super.myField = value
  }
}