Skip to main content

Приватні властивості класу

Приватна властивість, це властивість класу, ім'я якої починається з #: вона доступна тільки всередині самого класу, а ззовні повністю недоступна і навіть не видима. На відміну від старої угоди з підкресленням, це гарантія рівня мови, а не домовленість між розробниками.

Теорія

TL;DR

  • Синтаксис: #field у тілі класу, доступ через this.#field.
  • Ззовні obj.#field, це SyntaxError, а не undefined.
  • Приватними бувають і поля, і методи, і статичні члени (static #token).
  • Приватні поля не успадковуються: нащадок не бачить приватних полів батька.
  • Вони не перелічуються у for...in, Object.keys і не потрапляють у JSON.stringify.
  • Ім'я приватного поля не можна обчислити динамічно, воно завжди жорстко записане в коді.

Швидкий приклад

javascript
class User { #password = '12345'; // приватна властивість checkPassword(pwd) { return pwd === this.#password; } } const u = new User(); console.log(u.#password); // SyntaxError, напряму звернутися не можна console.log(u.password); // undefined console.log(u.checkPassword('12345')); // true

Тут:

  • #password, це приватна властивість,
  • вона доступна тільки всередині методів класу,
  • ззовні спроба звернення дає синтаксичну помилку, а не просто undefined.

Приватні поля й методи

Ховати можна не лише властивості, а й методи:

javascript
class Account { #balance = 0; #log(message) { console.log('[LOG]:', message); } deposit(amount) { this.#balance += amount; this.#log(`Баланс поповнено на ${amount}`); } getBalance() { return this.#balance; } } const acc = new Account(); acc.deposit(100); // acc.#log('test'); // Помилка, це приватний метод console.log(acc.getBalance()); // 100

Приватні методи зручні для допоміжної логіки, яку не треба показувати користувачеві класу.

Відмінність від звичайних властивостей:

ВластивістьВидимістьМожна змінити ззовні?Перелічується у for...in?
this.valueПублічнаТакТак
#valueПриватнаНіНі

Чому угода з підкресленням не підходить

До появи # розробники імітували приватність угодою: ставили _ перед іменем.

javascript
class User { _password = '12345'; }

Але це нічого не захищає:

javascript
const u = new User(); u._password = 'hacked'; // спокійно змінюється

#, це справжній захист на рівні мови, а не просто домовленість між людьми в команді.

Успадкування та приватна статика

Приватні поля не успадковуються і недоступні в підкласах:

javascript
class Parent { #secret = 'parent secret'; reveal() { console.log(this.#secret); } } class Child extends Parent { test() { console.log(this.#secret); // Помилка, це приватне поле батька } }

Кожен клас бачить тільки свої приватні поля, навіть якщо наслідує інший.

Статичні члени теж можуть бути приватними:

javascript
class Config { static #token = 'abc123'; static getToken() { return this.#token; } } console.log(Config.getToken()); // 'abc123' console.log(Config.#token); // Помилка

Це корисно, коли треба сховати конфіденційні дані рівня класу.

Реальний приклад і обмеження

Приватне поле #balance захищає дані від прямого втручання:

javascript
class BankAccount { #balance = 0; deposit(amount) { if (amount <= 0) throw new Error('Сума має бути додатною'); this.#balance += amount; } withdraw(amount) { if (amount > this.#balance) throw new Error('Недостатньо коштів'); this.#balance -= amount; } getBalance() { return this.#balance; } } const acc = new BankAccount(); acc.deposit(500); console.log(acc.getBalance()); // 500 acc.withdraw(200); console.log(acc.getBalance()); // 300 // acc.#balance = 100000; // Помилка, ззовні змінити не можна

Важливе обмеження: приватну властивість не можна створити динамічно. Імена приватних полів жорстко задані в коді:

javascript
const name = '#secret'; class A { [name] = 123; // Помилка, змінну тут використати не можна }

Так зроблено заради повної гарантії доступу: дістатися до поля можна лише через літерал з #.

Підсумкова таблиця:

ОсобливістьПриватна властивість (#field)
ВидимістьТільки всередині класу
ОголошенняЧерез #ім'я
Доступ ззовніПомилка, а не просто undefined
УспадкуванняНе передається нащадкам
Можна в статиціТак (static #secret)
Поєднується з геттерами та сетерамиТак
Створити динамічноНі

Типові помилки

  • Плутати #field і _field. Підкреслення, це лише угода, будь-який код може перезаписати таке поле.
  • Очікувати undefined ззовні. Звернення до obj.#field поза класом, це помилка ще на етапі парсингу, тому вона ламає весь файл, а не лише цей рядок.
  • Розраховувати на доступ із нащадка. Приватні поля батька не видно в підкласі; якщо потрібен доступ, використовуйте protected-подібний патерн через звичайне поле або геттер.
  • Перевіряти наявність поля через in на чужому об'єкті без обережності. Для приватних полів працює #field in obj, але тільки всередині класу, який їх оголошує.
  • Забувати, що приватні поля не серіалізуються. JSON.stringify(acc) не покаже #balance, тому для збереження стану потрібен явний метод.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.