Доступ к защищенным полям базового класса из производного (частный класс ES2019)

Я хотел бы получить доступ к закрытым полям базового класса из производных классов, не делая их общедоступными (что на других языках называется "защищенными").

Рассмотрим следующий класс:

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. Uncaught SyntaxError: частное поле '#privateProp' должно быть объявлено во включающем классе
  2. Uncaught SyntaxError: неожиданное частное поле

Обратите внимание, что этот код будет отлично работать, когда privateProp станет общедоступным, но я хочу добиться защищенного подобного поведения и получить доступ к "частным" полям, как любой язык, поддерживающий наследование.

Любая помощь будет оценена по достоинству.

2 ответа

Решение

вы можете создать частное свойство с методами получения и установки, имеющими ограниченный доступ, проверив, не принадлежит ли конструктор самому родительскому классу.

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);

Поля являются частными аналогично тому, как переменные имеют блочную область видимости; если собственность принадлежит определенномуclass, на него можно ссылаться только внутри этого класса. Если вы расширите класс, он не будет виден в производном классе.

Вы можете создать геттер / сеттер в суперклассе, если хотите иметь возможность делать с ним что-то из подкласса:

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();

Другие вопросы по тегам