9.1 基本概念
封裝 是物件導向程式設計(OOP)的一個關鍵概念,它允許隱藏對象的內部實現細節,並通過明確定義的接口提供對這些細節的訪問。這有助於提高安全性並簡化代碼管理。
封裝的優勢:
- 數據隱藏:封裝允許隱藏內部實現細節,僅提供對必要的方法和屬性的訪問。這可以防止對象的不當使用並提高代碼的安全性。
- 訪問控制:封裝允許控制對數據和方法的訪問,只有通過特定的方法才能改變對象的內部狀態。
- 可維護性:封裝提高了代碼的支持性,因為實現的更改不會影響類的外部接口。這允許在不更改使用該類的代碼的情況下更改實現。
- 改進測試:封裝允許隔離對象的內部實現,這簡化了單元測試並減少了副作用的可能性。
在 JavaScript 中,封裝是通過方法和屬性實現的,而從 ES2022 開始,還可以使用私有字段和方法。
9.2 通過閉包實現封裝
在 ES2022 引入私有字段之前,JavaScript 中的封裝通常通過閉包來實現。
例子:
- 變量
count
只在函數createCounter
內可用,外部無法訪問 - 方法
increment
、decrement
和getCount
可以與私有變量count
互動
JavaScript
function createCounter() {
let count = 0; // 私有變量
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 ES2022 中的私有字段
在 ES2022 中,引入了使用符號 #
聲明的私有字段和方法。私有字段和方法不能從類外部訪問或更改。
例子:
- 私有字段
#name
和#age
使用符號#
聲明 - 方法
getName
、getAge
、setName
和setAge
允許與私有字段互動 - 從類外部訪問私有字段會導致錯誤
JavaScript
class Person {
#name; // 私有字段
#age; // 私有字段
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); // 錯誤: 私有字段不可訪問
9.4 私有方法
私有方法也可以使用符號 #
聲明,並且在類外部不可訪問。
例子:
- 私有字段
#balance
和私有方法#logTransaction
用於管理對象BankAccount
的狀態 - 私有方法
#logTransaction
在公開方法deposit
和withdraw
中調用以記錄交易
JavaScript
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); // 錯誤: 私有方法不可訪問
GO TO FULL VERSION