1. Prototype là gì?
Trong JavaScript, Prototype là một cơ chế cho phép các đối tượng (object) kế thừa các phương thức và thuộc tính từ các đối tượng khác. Mỗi object trong JavaScript đều có một liên kết ẩn gọi là [[Prototype]]
, thường được truy cập thông qua __proto__
hoặc sử dụng Object.getPrototypeOf()
. Khi bạn tạo một object từ một hàm khởi tạo (constructor function), nó sẽ tự động liên kết với thuộc tính prototype
của hàm đó.
Ví dụ:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound.`);
};
const dog = new Animal('Dog');
dog.speak(); // Dog makes a sound.
Trong ví dụ này, Animal
là một constructor function. Animal.prototype
chứa phương thức speak
, và đối tượng dog
được tạo ra từ Animal
có thể gọi được phương thức này vì nó liên kết với Animal.prototype
.
2. Chuỗi Prototype (Prototype Chain)
Chuỗi Prototype là khái niệm mô tả cách các đối tượng liên kết với nhau thông qua prototype. Khi bạn gọi một phương thức hoặc thuộc tính trên một object, JavaScript sẽ tìm kiếm nó trong chính object đó trước. Nếu không tìm thấy, nó sẽ tiếp tục tìm kiếm trong prototype của object, rồi đến prototype của prototype, cho đến khi gặp null
(đỉnh của chuỗi prototype).
Ví dụ về Chuỗi Prototype:
function A() {}
function B() {}
// Thiết lập chuỗi prototype, cho phép B thừa kế các phương thức từ A
Object.setPrototypeOf(B.prototype, A.prototype);
A.prototype.foo = function() {
console.log('foo');
}
B.prototype.bar = function() {
console.log('bar');
}
// Thêm một phương thức vào Object.prototype, cho phép tất cả các object sử dụng phương thức này
Object.prototype.barbaz = function() {
console.log('barbaz');
}
// Thêm một phương thức vào Function.prototype, cho phép tất cả các hàm (function) sử dụng phương thức này
Function.prototype.foobar = function() {
console.log('foobar');
}
var a = new A(); // Tạo một đối tượng a từ constructor A
var b = new B(); // Tạo một đối tượng b từ constructor B
// Thêm phương thức baz trực tiếp vào object b
b.baz = function() {
console.log('baz');
}
// Các lệnh dưới đây mô tả cách hoạt động của chuỗi prototype
b.baz(); // 'baz', phương thức baz nằm trực tiếp trong object b, không thông qua prototype chain
b.bar(); // 'bar', vì bar nằm trong B.prototype, được truy cập thông qua prototype chain
b.foo(); // 'foo', vì foo nằm trong A.prototype (do B.prototype liên kết đến A.prototype)
b.barbaz(); // 'barbaz', vì barbaz nằm trong Object.prototype, được liên kết mặc định bởi A.prototype
// b.foobar(); // Gây ra lỗi TypeError: b.foobar is not a function vì foobar không nằm trong prototype chain của object b, vì thế engine sẽ trả về undefined vì không tìm thấy foobar
3. Sự Khác Nhau Giữa [[Prototype]]
và .prototype
-
Mọi object đều có liên kết
[[Prototype]]
: Đây là liên kết ẩn mà mọi object trong JavaScript đều sở hữu.[[Prototype]]
xác định object đó liên kết đến đối tượng nào trong chuỗi prototype. Để truy cập, có thể sử dụng__proto__
hoặcObject.getPrototypeOf()
. -
Function cũng là một object: Trong JavaScript, hàm thực chất là một object. Do đó, nó cũng có liên kết
[[Prototype]]
. Ngoài ra, các function còn có thuộc tính đặc biệt gọi là.prototype
, chứa các phương thức và thuộc tính chung mà các object khác có thể liên kết.
4. Khi Nào Cần Chú Ý Đến Chuỗi Prototype?
- Hiệu suất: Nếu chuỗi prototype quá dài, việc tìm kiếm các thuộc tính hoặc phương thức có thể ảnh hưởng đến hiệu suất.
- Ghi đè phương thức: Việc ghi đè phương thức trong chuỗi prototype cần được thực hiện cẩn thận để tránh xung đột hoặc thay đổi hành vi không mong muốn.
- Chia sẻ phương thức: Prototype là một cách tuyệt vời để chia sẻ phương thức giữa các đối tượng mà không phải sao chép chúng vào mỗi object, giúp tiết kiệm bộ nhớ.
Kết Luận
Hiểu về prototype và chuỗi prototype là các khái niệm cốt lõi trong JavaScript. Chúng cung cấp một cơ chế mạnh mẽ cho việc tái sử dụng và chia sẻ phương thức giữa các đối tượng. Bằng cách nắm vững cách hoạt động của chuỗi prototype, bạn có thể viết mã JavaScript hiệu quả và linh hoạt hơn.
source: viblo