9.1 Główne pojęcia
Enkapsulacja — to jedna z kluczowych koncepcji programowania obiektowego (OOP), która pozwala ukrywać wewnętrzne szczegóły implementacji obiektu i zapewniać dostęp do tych szczegółów przez ściśle określone interfejsy. Pomaga to poprawić bezpieczeństwo i uprościć zarządzanie kodem.
Zalety enkapsulacji:
- Ukrywanie danych: enkapsulacja pozwala ukrywać wewnętrzne szczegóły implementacji i zapewniać dostęp tylko do niezbędnych metod i właściwości. To zapobiega niepoprawnemu używaniu obiektów i poprawia bezpieczeństwo kodu.
- Kontrola dostępu: enkapsulacja pozwala kontrolować dostęp do danych i metod, dając możliwość zmieniania wewnętrznego stanu obiektu tylko przez określone metody.
- Wspieralność: enkapsulacja poprawia wsparcie kodu, ponieważ zmiany w implementacji nie wpływają na zewnętrzny interfejs klasy. Pozwala to na wprowadzanie zmian w implementacji bez zmieniania kodu, który używa klasy.
- Poprawa testowania: enkapsulacja pozwala izolować wewnętrzną implementację obiektu, co upraszcza testy jednostkowe i zmniejsza prawdopodobieństwo powstawania efektów ubocznych.
W JavaScript enkapsulacja jest realizowana przy użyciu metod i właściwości, a począwszy od ES2022, dostępne są również pola i metody prywatne.
9.2 Enkapsulacja przez domknięcia
Przed wprowadzeniem prywatnych pól w ES2022, enkapsulacja w JavaScript często osiągana była za pomocą domknięć.
Przykład:
- Zmienna
count
jest dostępna tylko wewnątrz funkcjicreateCounter
i niedostępna z zewnątrz - Metody
increment
,decrement
igetCount
mogą interakcjonować z prywatną zmiennącount
function createCounter() {
let count = 0; // prywatna zmienna
return {
increment() {
count++;
console.log(count);
},
decrement() {
count--;
console.log(count);
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
console.log(counter.getCount()); // 2
counter.decrement(); // 1
9.3 Pola prywatne w ES2022
W ES2022 wprowadzono pola i metody prywatne, które deklaruje się przy użyciu symbolu #
. Pola i metody prywatne nie mogą być dostępne ani zmieniane poza klasą.
Przykład:
- Pola prywatne
#name
i#age
są deklarowane przy użyciu symbolu#
- Metody
getName
,getAge
,setName
isetAge
pozwalają na interakcję z polami prywatnymi - Próba dostępu do pól prywatnych spoza klasy prowadzi do błędu
class Person {
#name; // pole prywatne
#age; // pole prywatne
constructor(name, age) {
this.#name = name;
this.#age = age;
}
getName() {
return this.#name;
}
getAge() {
return this.#age;
}
setName(name) {
this.#name = name;
}
setAge(age) {
if (age > 0) {
this.#age = age;
}
}
}
const person = new Person('Alice', 30);
console.log(person.getName()); // "Alice"
console.log(person.getAge()); // 30
person.setName('Bob');
person.setAge(25);
console.log(person.getName()); // "Bob"
console.log(person.getAge()); // 25
console.log(person.#name); // Błąd: pole prywatne jest niedostępne
9.4 Metody prywatne
Metody prywatne również mogą być deklarowane przy użyciu symbolu #
i być niedostępne spoza klasy.
Przykład:
- Pole prywatne
#balance
i prywatna metoda#logTransaction
są używane do zarządzania stanem obiektuBankAccount
- Prywatna metoda
#logTransaction
jest wywoływana wewnątrz publicznych metoddeposit
iwithdraw
do rejestrowania transakcji
class BankAccount {
#balance;
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
this.#logTransaction('deposit', amount);
}
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
this.#logTransaction('withdraw', amount);
}
}
getBalance() {
return this.#balance;
}
#logTransaction(type, amount) {
console.log(`Transaction: ${type} ${amount}`);
}
}
const account = new BankAccount(1000);
account.deposit(500); // "Transaction: deposit 500"
console.log(account.getBalance()); // 1500
account.withdraw(200); // "Transaction: withdraw 200"
console.log(account.getBalance()); // 1300
account.#logTransaction('test', 100); // Błąd: metoda prywatna jest niedostępna
GO TO FULL VERSION