В прошлых темах мы использовали класс, свойства и методы которого были досупны извне, и соответственно мы могли к им обратиться в любом месте программы. Например:
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
print(){
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
const tom = new Person("Tom", 37);
tom.name = "Sam";
tom.age = -45;
tom.print(); // Name: Sam Age: -45
С одной стороны, это замечательно, что мы можем использовать функциональность класса в своей программе, обращаться к его свойствам, методам. Но это может быть источником потенциальных проблем. Как видно в примере выше, мы можем изменить имя человека. Но что, если мы не хотим, чтобы в программе можно было менять начальное имя? Также мы можем изменить возраст человека, но изменить его на любое число, которое может предствлять некорректный возраст (например, отрицательный).
Иногда необходимо, чтобы к данным или действиям извне класса нельзя было обратиться, и чтобы к ним можно было обращаться только внутри этого же класса. Или иными словами, сделать свойства и методы класса приватными - доступными только для этого класса. И язык JavaScript предоставляет для этого необходимый инструментарий. Для этого название полей и методов должно начинаться с символа решетки #.
Названия приватных полей предваряется символом #:
class Person{
#name;
#age;
constructor(name, age){
this.#name = name;
this.#age = age;
}
print(){
console.log(`Name: ${this.#name} Age: ${this.#age}`);
}
}
const tom = new Person("Tom", 37);
// tom.#name = "Sam"; // ! Ошибка - нельзя обратиться к приватному полю
// tom.#age = -45; // ! Ошибка - нельзя обратиться к приватному полю
tom.print(); // Name: Tom Age: 37
В примере выше определены приватные поля #name и #age. Установить и получить их значение можно только внури класса Person.
Вне его они не доступны. Поэтому при попытке обратиться к ним через имя объекта, мы получим ошибку:
tom.#name = "Sam"; // ! Ошибка - нельзя обратиться к приватному полю tom.#age = -45; // ! Ошибка - нельзя обратиться к приватному полю
Если потребуется как-то к ним все-таки обратиться, то мы можем определить для этого методы. Например, выше метод print() получает их значения и выводит на консоль.
Подобным образом можно определить и методы для установки значения:
class Person{
#name;
#age= 1;
constructor(name, age){
this.#name = name;
this.setAge(age);
}
setAge(age){
if (age > 0 && age < 110) this.#age = age;
}
print(){
console.log(`Name: ${this.#name} Age: ${this.#age}`);
}
}
const tom = new Person("Tom", 37);
tom.print(); // Name: Tom Age: 37
tom.setAge(22);
tom.print(); // Name: Tom Age: 22
tom.setAge(-1234);
tom.print(); // Name: Tom Age: 22
В данном случае метод setAge проверяет корректность переданного значения, и если оно корректно, переустанавливает возраст.
Названия приватных методов также предваряются символом #:
class Person{
#name = "undefined";
#age = 1;
constructor(name, age){
this.#name = this.#checkName(name);
this.setAge(age);
}
#checkName(name){
if(name!=="admin") return name;
}
setAge(age){
if (age > 0 && age < 110) this.#age = age;
}
print(){
console.log(`Name: ${this.#name} Age: ${this.#age}`);
}
}
const tom = new Person("Tom", 37);
tom.print(); // Name: Tom Age: 37
const bob = new Person("admin", 41);
bob.print(); // Name: Undefined Age 41
//let personName = bob.#checkName("admin"); // ! Ошибка - нельзя обратится к приватному методу
В примере выше определен приватный метод #checkName(), который выполняет условную проверку имени - ели оно не равно "admin", то возвращает переданное значение. (К примеру, мы не хотим,
чтобы имя пользователя было "admin"). И также вне класса мы не можем обратиться к этому методу:
let personName = bob.#checkName("admin"); // ! Ошибка
Как правило, подобные приватные методы используются для выполнения каких-то вспомогательных действий, как, например, валидация в примере выше, и которые нет смысла делать доступнми из вне.