Закрытые поля, определенные спецификацией ECMAScript¶
Помимо сокрытия полей класса от внешней среды с помощью модификатора доступа private
, присущего исключительно TypeScript, существует возможность прибегнуть к механизму, предусмотренному спецификацией ECMAScript.
Нативный закрытый (private) модификатор доступа¶
Для того чтобы поля класса оставались закрытыми после компиляции в JavaScript, необходимо прибегнуть к модификатору, определенному спецификацией ECMAScript #
, который указывается в качестве префикса их идентификаторов (имен) #identifier
.
Доступ к защищенному полю класса ограничивается областью видимости класса, в котором оно объявлено, а при обращении к нему необходимо также указывать символ решетки.
class Animal {
#isLife: boolean = true; // защищенное поле класса
get isLife() {
return this.#isLife;
}
}
let animal = new Animal();
console.log(animal.isLife); // обращение к аксессору, а не защищенному полю
Поскольку доступ ограничивается областью видимости класса, потомки не могут обращаться к защищенным полям своих предков.
class Animal {
#isLife: boolean = true; // защищенное поле класса
}
/**
* Error!
*
* Class 'Bird' incorrectly extends base class 'Animal'.
* Property '#isLife' is not accessible outside class 'Animal' because
* it has a private identifier.ts(18013)
*/
class Bird extends Animal {
constructor() {
super();
this.#isLife;
}
}
В отличие от модификатора доступа private
, этот механизм не может быть применён к методам и акссесорам класса, но так как за его появлением стоит спецификация ECMAScript, то он продолжает действовать в скомпилированной программе. Именно поэтому, в отличие от сценария с модификатором доступа private
, потомки могут без страха нарушить ожидаемый ход выполнения программы и объявлять защищенные поля, чьи идентификаторы идентичны объявлениям в их супер-классах.
Сценарий с модификатором доступа private:
class Animal {
private _isLife: boolean = true;
}
/**
* Error!
*
* Class 'Bird' incorrectly extends base class 'Animal'.
* Types have separate declarations of a private property '_isLife'.ts(2415)
*/
class Bird extends Animal {
private _isLife: boolean = false;
}
Сценарий с защищенными полями, предусмотренными спецификацией ECMAScript:
class Animal {
#isLife: boolean = true;
}
/**
* Ok!
*/
class Bird extends Animal {
#isLife: boolean = false;
}
И в заключение, стоит упомянуть, что существует несколько нюансов — один из них заключается в том, что закрытые поля нельзя объявлять непосредственно в конструкторе.
class Animal {
// Parameter declaration expected.ts(1138)
constructor(#isLife = true) {}
}
Другой нюанс связан с тем, что код, содержащий закрытые поля класса, может быть скомпилирован исключительно в версии es6
и выше.