【问题标题】:Accessing protected fields of base class from derived (ES2019 private class)从派生(ES2019 私有类)访问基类的受保护字段
【发布时间】:2020-07-28 05:15:51
【问题描述】:

我想从派生类访问基类的私有字段而不将它们公开(在其他语言中称为“受保护”)。

考虑以下类:

class Animal {

  #privateProp;

  constructor() {

  this.#privateProp = 12;

  }
}

现在是扩展类:

class Cat extends Animal {

  constructor() {

    super();
  }

  doIt() {

    console.log(this.#privateProp) // 1 below
    console.log(super.#privateProp) // 2 below
  }
}

我想像受保护一样执行:

new Cat().doIt();

但得到(分别):

  1. 未捕获的语法错误:必须在封闭类中声明私有字段“#privateProp”
  2. 未捕获的 SyntaxError:意外的私有字段

请注意,当 privateProp 公开时,此代码将完美运行,但我想实现类似受保护的行为并像任何支持继承的语言一样访问“私有”字段。

任何帮助将不胜感激。

【问题讨论】:

  • Umm ..“private”实际上是私有的,所以不能在课堂外访问。
  • 私有字段是私有的是有原因的 :)
  • 好吧对不起,让我把它改成“受保护”
  • 看看这个以更好地理解stackoverflow.com/questions/34517581/…
  • 所以看完之后,我想在JS中还没有直接的方法来实现这种行为。

标签: javascript private ecmascript-next class-fields


【解决方案1】:

您可以使用 getter 和 setter 方法创建私有属性 通过检查构造函数是否不属于 父类本身。

class Animal {
  #privateProp = 12;
  set Prop(val) {
    if (this.constructor.name !== 'Animal')
      return this.#privateProp = val;
    throw new Error('Cannot Access Protected property');
  }
  get Prop() {
    if (this.constructor.name !== 'Animal')
      return this.#privateProp;
    throw new Error('Cannot Access Protected property');
  }
}

class Cat extends Animal {
  get Prop() {
    return super.Prop;
  }

  set Prop(val) {
    super.Prop = val
  }
}

let cat = new Cat();
console.log(cat.Prop)
cat.Prop = 22
console.log(cat.Prop)

console.log(new Animal().Prop);

【讨论】:

  • 漂亮!谢谢
  • 如果您提供公共 getter 和 setter,这不再是私有(或受保护)属性。
  • @Bergi 它们不是受保护的变量,而是实现这一目标的解决方法,这里只有父类或子类可以访问变量,而不是任何其他实际上是受保护的变量行为的类。如果我们需要在其他类中访问这些变量,我们可以在父类中实现另一个 getter 和 setter 包装器。
  • @AZ_ 否。每个人都可以从任何地方访问子类实例的这些属性,正如您的代码 (console.log(cat.Prop); cat.Prop = 22) 所示。它不仅限于子类中的代码。
  • @Bergi 这样您就不会访问父级的受保护属性Prop,而是访问子级的公共属性Prop。我只是保持它在父母中的样子。在孩子中,OP 可以选择不让 getter 和 setter 完全返回父道具。可能是return super.Prop+1;或者只在方法中使用。
【解决方案2】:

字段是私有的,类似于变量的块作用域;如果某个属性是某个class 的私有属性,则它只能在该类中被引用。如果扩展类,它在派生类中将不可见。

如果您希望能够从子类中对它做一些事情,您可以在超类上创建一个 getter/setter:

class Animal {
  #privateProp = 12;
  setProp(val) {
    this.#privateProp = val;
  }
  getProp() {
    return this.#privateProp;
  }
}
class Cat extends Animal {
  doIt() {
    console.log(this.getProp());
  }
}
new Cat().doIt();

另一种方法是将“私有”字段定义为仅适用于类声明的 WeakMap:

const { Animal, Cat } = (() => {
  const privateProps = new WeakMap();
  class Animal {
    constructor() {
      privateProps.set(this, 12);
    }
  }
  class Cat extends Animal {
    doIt() {
      console.log(privateProps.get(this));
    }
  }
  return { Animal, Cat };
})();
new Cat().doIt();

【讨论】:

  • 也可以创建一个实际的getter和setter方法,即get privateProp(){}
  • 这不是让#privateProp 有效地公开吗?所以任何人都可以去 new Animal().getProp() ?
  • @TamirNakar 子类与超类的私有字段交互的唯一方法是让超类公开允许以某种方式进行交互的功能。
  • @CertainPerformance,同意。但我希望尽可能少地进行交互。在 java for instane 中,您将该字段定义为受保护的,并且只有派生类才能访问此属性。这种行为可以实现吗?
  • @TamirNakar 不幸的是,使用当前的语法规则,并不是真的。如果是我,在这种情况下,我会创建一个仅适用于类的 WeakMap
猜你喜欢
  • 2016-03-11
  • 2014-08-27
  • 1970-01-01
  • 2011-06-08
  • 2019-01-20
  • 1970-01-01
  • 1970-01-01
  • 2014-05-01
  • 2016-04-07
相关资源
最近更新 更多