Доступ к защищенным полям базового класса из производного (частный класс 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();
Но получает (соответственно):
- Uncaught SyntaxError: частное поле '#privateProp' должно быть объявлено во включающем классе
- 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();