JavaScript - Object Accessors

Chào mừng các bạn đang học lập trình! Hôm nay, chúng ta sẽ khám phá thế giới fascinante của JavaScript Object Accessors. Đừng lo lắng nếu bạn mới bắt đầu học lập trình; tôi sẽ hướng dẫn bạn từng bước, giống như tôi đã làm cho hàng trăm học sinh trong những năm dạy học của mình. Vậy, hãy lấy một cốc cà phê (hoặc thức uống yêu thích của bạn), và cùng nhau bắt đầu hành trình thú vị này nhé!

JavaScript - Object Accessors

Các thuộc tính của Object Accessor

Trước khi chúng ta đi sâu vào chi tiết về accessors, hãy cùng làm mới lại một chút về đối tượng. Trong JavaScript, đối tượng là những containner chứa dữ liệu và chức năng liên quan. Hãy tưởng tượng chúng như những phiên bản kỹ thuật số của các đối tượng thực tế. Ví dụ, một đối tượng xe có thể có các thuộc tính như màu sắc, thương hiệu và tốc độ.

Bây giờ, các thuộc tính accessor là những loại thuộc tính đặc biệt cho phép chúng ta lấy hoặc đặt giá trị một cách kiểm soát hơn. Chúng giống như những người bảo vệ dữ liệu của đối tượng. Hãy cùng khám phá thêm với một số ví dụ.

Ví dụ cơ bản về đối tượng

let car = {
brand: "Toyota",
model: "Camry",
year: 2022
};

console.log(car.brand); // Output: Toyota

Trong ví dụ này, chúng ta đang truy cập trực tiếp thuộc tính brand. Nhưng nếu chúng ta muốn có nhiều kiểm soát hơn trong việc truy cập hoặc thay đổi các thuộc tính này? Đó là lúc accessors được sử dụng!

JavaScript Getters

Getters là các phương thức lấy giá trị của một thuộc tính cụ thể. Chúng cho phép chúng ta tính toán một giá trị ngay lập tức thay vì chỉ trả về giá trị đã lưu. Hãy xem chúng ta có thể sử dụng getter như thế nào:

let person = {
firstName: "John",
lastName: "Doe",
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
};

console.log(person.fullName); // Output: John Doe

Trong ví dụ này, fullName là một getter. Nó tính toán và trả về tên đầy đủ bằng cách kết hợp firstNamelastName. Chú ý rằng chúng ta sử dụng nó như một thuộc tính (person.fullName) thay vì gọi nó như một phương thức (person.fullName()).

JavaScript Setters

Setters là counterparts của getters. Chúng đặt giá trị của một thuộc tính cụ thể, cho phép chúng ta thực thi mã mỗi khi thuộc tính cố gắng thay đổi. Dưới đây là một ví dụ:

let thermostat = {
_temperature: 22, // Quy ước: gạch dưới chỉ thị một biến "riêng tư"
get temperature() {
return this._temperature;
},
set temperature(value) {
if (value > 30) {
console.log("It's too hot!");
} else if (value < 10) {
console.log("It's too cold!");
} else {
this._temperature = value;
}
}
};

thermostat.temperature = 25; // Đặt nhiệt độ là 25
console.log(thermostat.temperature); // Output: 25

thermostat.temperature = 35; // Output: It's too hot!
console.log(thermostat.temperature); // Output: 25 (không thay đổi)

Trong ví dụ này, chúng ta đã tạo một đối tượng thermostat với một getter và setter cho nhiệt độ. Setter kiểm tra xem nhiệt độ mới có trong phạm vi cho phép trước khi đặt nó.

JavaScript Object Methods vs. Getters/Setters

Bạn có thể đang tự hỏi, "Tại sao sử dụng getters và setters khi chúng ta có thể chỉ cần sử dụng phương thức thông thường?" Câu hỏi tuyệt vời! Hãy so sánh:

let rectangle = {
width: 5,
height: 3,
// Phương thức
calculateArea: function() {
return this.width * this.height;
},
// Getter
get area() {
return this.width * this.height;
}
};

console.log(rectangle.calculateArea()); // Output: 15
console.log(rectangle.area); // Output: 15

Cả calculateArea()area đều cho chúng ta cùng một kết quả, nhưng getter area trông và cảm thấy giống như một thuộc tính hơn. Nó trực quan hơn và có thể làm cho mã của chúng ta sạch sẽ hơn, đặc biệt khi chúng ta đang làm việc với các thuộc tính tính toán.

Chất lượng dữ liệu và bảo mật

Getters và setters không chỉ tiện lợi; chúng còn là những công cụ mạnh mẽ để duy trì chất lượng và bảo mật dữ liệu. Chúng cho phép chúng ta:

  1. Xác minh dữ liệu trước khi đặt nó
  2. Tính toán các giá trị ngay lập tức
  3. Kiểm soát truy cập vào các thuộc tính nội bộ

Hãy xem một ví dụ minh họa những lợi ích này:

let bankAccount = {
_balance: 1000, // "_" quy ước cho thuộc tính "riêng tư"
get balance() {
return `$${this._balance}`;
},
set balance(value) {
if (typeof value === 'number' && value >= 0) {
this._balance = value;
} else {
console.log("Invalid balance input");
}
}
};

console.log(bankAccount.balance); // Output: $1000
bankAccount.balance = 1500;
console.log(bankAccount.balance); // Output: $1500
bankAccount.balance = -500; // Output: Invalid balance input
console.log(bankAccount.balance); // Output: $1500 (không thay đổi)

Trong ví dụ này, chúng ta đang đảm bảo rằng số dư luôn là một số không âm và định dạng nó thành tiền tệ khi truy cập.

Định nghĩa getters/setters sử dụng Object.defineProperty()

Đôi khi, chúng ta có thể muốn thêm getters và setters vào các đối tượng hiện có. Chúng ta có thể làm điều này bằng cách sử dụng Object.defineProperty(). Dưới đây là cách thực hiện:

let car = {
brand: "Toyota",
model: "Camry"
};

Object.defineProperty(car, 'fullName', {
get: function() {
return `${this.brand} ${this.model}`;
},
set: function(value) {
[this.brand, this.model] = value.split(' ');
}
});

console.log(car.fullName); // Output: Toyota Camry
car.fullName = "Honda Civic";
console.log(car.brand); // Output: Honda
console.log(car.model); // Output: Civic

Phương pháp này đặc biệt hữu ích khi bạn đang làm việc với các đối tượng mà bạn không tạo ra hoặc khi bạn muốn thêm accessors một cách động.

Lý do để sử dụng getters và setters

Tóm lại, đây là những lý do chính chúng ta sử dụng getters và setters:

Lý do Mô tả
Đóng gói dữ liệu Kiểm soát truy cập vào các thuộc tính nội bộ
Thuộc tính tính toán Tính toán các giá trị ngay lập tức
Xác minh dữ liệu Đảm bảo tính toàn vẹn dữ liệu trước khi đặt giá trị
Tương thích ngược Thêm mới chức năng mà không thay đổi mã hiện có
Cú pháp sạch sẽ Truy cập các thuộc tính tính toán như các thuộc tính thông thường

Nhớ rằng, lập trình là về việc viết mã không chỉ功能性 mà còn sạch sẽ, dễ bảo trì và an toàn. Getters và setters là những công cụ mạnh mẽ để đạt được những mục tiêu này.

Và đây là tất cả, các bạn! Chúng ta đã cùng nhau hành trình qua thế giới của JavaScript Object Accessors. Tôi hy vọng hướng dẫn này đã mang lại cho bạn nhiều kiến thức như nó đã vui vẻ cho tôi khi viết. Nhớ rằng, thực hành là cách để trở nên hoàn hảo, vì vậy đừng ngần ngại thử nghiệm các khái niệm này trong mã của bạn. Chúc các bạn lập trình vui vẻ!

Credits: Image by storyset