9.1 Khái niệm cơ bản
Đóng gói - đây là một trong những khái niệm chính của lập trình hướng đối tượng (OOP), giúp ẩn đi những chi tiết bên trong của việc triển khai đối tượng và cung cấp quyền truy cập vào những chi tiết này qua các giao diện xác định rõ ràng. Điều này giúp cải thiện bảo mật và đơn giản hóa việc quản lý mã.
Lợi ích của đóng gói:
- Ẩn dữ liệu: đóng gói cho phép ẩn đi các chi tiết triển khai bên trong và chỉ cung cấp quyền truy cập vào các phương thức và thuộc tính cần thiết. Điều này ngăn chặn việc sử dụng sai đối tượng và cải thiện bảo mật của mã.
- Kiểm soát truy cập: đóng gói cho phép kiểm soát quyền truy cập vào dữ liệu và phương thức, cho phép thay đổi trạng thái bên trong của đối tượng chỉ qua các phương thức xác định.
- Dễ bảo trì: đóng gói cải thiện khả năng hỗ trợ mã vì các thay đổi trong việc triển khai không ảnh hưởng đến giao diện bên ngoài của lớp. Điều này cho phép thực hiện thay đổi trong việc triển khai mà không cần thay đổi mã sử dụng lớp.
- Cải thiện kiểm thử: đóng gói cho phép cô lập việc triển khai bên trong của đối tượng, giúp dễ dàng kiểm thử đơn vị và giảm thiểu khả năng xảy ra tác dụng phụ.
Trong JavaScript, đóng gói được thực hiện bằng cách sử dụng phương thức và thuộc tính, và bắt đầu từ ES2022, cũng đã có các trường và phương thức riêng tư.
9.2 Đóng gói qua closures
Trước khi có các trường riêng tư trong ES2022, đóng gói trong JavaScript thường được thực hiện qua closures.
Ví dụ:
- Biến
count
chỉ có thể truy cập được bên trong hàmcreateCounter
và không thể truy cập từ bên ngoài - Các phương thức
increment
,decrement
vàgetCount
có thể tương tác với biến riêng tưcount
function createCounter() {
let count = 0; // biến riêng tư
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 Trường riêng tư trong ES2022
Trong ES2022, đã có trường và phương thức riêng tư, được khai báo bằng cách sử dụng ký hiệu #
. Trường và
phương thức riêng tư không thể truy cập hoặc thay đổi từ bên ngoài lớp.
Ví dụ:
- Các trường riêng tư
#name
và#age
được khai báo bằng ký hiệu#
- Các phương thức
getName
,getAge
,setName
vàsetAge
cho phép tương tác với các trường riêng tư - Thử truy cập vào các trường riêng tư từ bên ngoài lớp sẽ gây lỗi
class Person {
#name; // trường riêng tư
#age; // trường riêng tư
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); // Lỗi: trường riêng tư không truy cập được
9.4 Phương thức riêng tư
Phương thức riêng tư cũng có thể được khai báo bằng cách sử dụng ký hiệu #
và không thể truy cập từ bên ngoài lớp.
Ví dụ:
- Trường riêng tư
#balance
và phương thức riêng tư#logTransaction
được sử dụng để quản lý trạng thái của đối tượngBankAccount
- Phương thức riêng tư
#logTransaction
được gọi bên trong các phương thức công khaideposit
vàwithdraw
để ghi lại các giao dịch
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); // Lỗi: phương thức riêng tư không truy cập được
GO TO FULL VERSION