25-08-24 18:59:40
В современном JavaScript (с ECMAScript 2020) вы можете создавать по-настоящему приватные свойства и методы с использованием синтаксиса #. Эти свойства и методы строго приватны и не могут быть доступны извне.
class Person {
// Приватное свойство
#age = 0;
constructor(name, age) {
this.name = name;
this.#age = age;
}
// Приватный метод
#calculateBirthYear() {
const currentYear = new Date().getFullYear();
return currentYear - this.#age;
}
// Публичный метод
getBirthYear() {
return this.#calculateBirthYear();
}
}
const person = new Person('Алиса', 30);
console.log(person.name); // Вывод: Алиса
console.log(person.getBirthYear()); // Вывод: (текущий год - 30)
console.log(person.#age); // Ошибка: Приватное поле '#age' должно быть объявлено в содержащем классе
console.log(person.#calculateBirthYear()); // Ошибка: Приватное поле '#calculateBirthYear' должно быть объявлено в содержащем классе
В этом примере:
Как упоминалось ранее, в JavaScript нет нативной поддержки защищенных свойств и методов. Однако разработчики часто используют соглашение о наименовании (с использованием _), чтобы указать, что свойство или метод предназначены для использования как защищенные.
class Vehicle {
// Защищенное (по соглашению) свойство
_fuelLevel = 100;
constructor(make, model) {
this.make = make;
this.model = model;
}
// Защищенный (по соглашению) метод
_consumeFuel(amount) {
this._fuelLevel -= amount;
}
drive() {
if (this._fuelLevel > 0) {
this._consumeFuel(10);
console.log(`${this.make} ${this.model} едет.`);
} else {
console.log(`${this.make} ${this.model} закончился бензин.`);
}
}
}
class ElectricCar extends Vehicle {
charge() {
this._fuelLevel = 100; // Прямой доступ к "защищенному" свойству
console.log(`${this.make} ${this.model} полностью заряжен.`);
}
}
const car = new ElectricCar('Tesla', 'Model 3');
car.drive(); // Вывод: Tesla Model 3 едет.
car.charge(); // Вывод: Tesla Model 3 полностью заряжен.
console.log(car._fuelLevel); // Вывод: 100 (но должно быть рассматриваемо как "защищенное")
В этом примере:
Приватные (#):
Защищенные (по соглашению, _):
Вы можете комбинировать приватные и защищенные методы, чтобы добиться баланса между строгой инкапсуляцией и контролируемым доступом в подклассах.
class BankAccount {
// Приватное свойство
#balance = 0;
constructor(accountHolder, initialDeposit) {
this.accountHolder = accountHolder;
this.#balance = initialDeposit;
}
// Защищенный (по соглашению) метод
_logTransaction(amount, type) {
console.log(`Транзакция: ${type} на сумму $${amount} для ${this.accountHolder}`);
}
// Публичный метод
deposit(amount) {
this.#balance += amount;
this._logTransaction(amount, 'Депозит');
}
withdraw(amount) {
if (this.#balance >= amount) {
this.#balance -= amount;
this._logTransaction(amount, 'Снятие');
} else {
console.log('Недостаточно средств.');
}
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount('Джон Доу', 1000);
account.deposit(500); // Вывод: Транзакция: Депозит на сумму $500 для Джон Доу
account.withdraw(300); // Вывод: Транзакция: Снятие на сумму $300 для Джон Доу
console.log(account.getBalance()); // Вывод: 1200
console.log(account.#balance); // Ошибка: Приватное поле '#balance' должно быть объявлено в содержащем классе
console.log(account._logTransaction(100, 'Проверка')); // Не рекомендуется, хотя технически возможно
В этом примере: