+2

Bạn có đang hiểu đúng về Prototype trong Javascript?

1. Prototype là gì?

Nguồn: devRant

Trong JavaScript, Prototype là cơ chế cho phép các đối tượng (object) "thừa kế" 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 thông qua 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ó có prototype liên kết đến Animal.prototype.

2. Prototype Chain

Prototype Chain 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 object đó trước. Nếu không tìm thấy, nó sẽ tiếp tục tìm trong prototype của object, rồi đến prototype của prototype, cứ thế tiếp tục cho đến khi gặp null (đỉnh của chuỗi prototype).

Ví dụ về Prototype Chain:

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

Lưu ý quan trọng về [[Prototype]].prototype:

  • Mọi object đều có [[Prototype]]: Đây là liên kết ẩn (internal link) mà mọi object trong JavaScript đều có. [[Prototype]] xác định object đó liên kết đến đối tượng nào trong chuỗi prototype. Nó có thể được truy cập thông qua __proto__ hoặc Object.getPrototypeOf().

  • Function cũng là object: Trong JavaScript, hàm (function) thực chất là một object. Do đó, nó cũng có liên kết [[Prototype]]. Bên cạnh đó, các function có một thuộc tính đặc biệt gọi là .prototype (được hiển thị màu xanh dương trong sơ đồ). Thuộc tính này 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, chẳng hạn như các phương thức cơ bản của Object.prototype như toString(), valueOf(), hay hasOwnProperty(), hoặc các phương thức như bind(), call(), apply() của Function.prototype. Bản thân .prototype cũng là một object nên cũng có [[Prototype]] riêng, tạo ra một chuỗi liên kết trong prototype chain.

Nguồn: Dan D Kim

Sơ đồ Prototype Chain:

Trong ví dụ trên:

  • B.prototype có liên kết với A.prototype thông qua Object.setPrototypeOf().
  • Đối tượng b có thể truy cập các phương thức từ cả B.prototype, A.prototypeObject.prototype nhờ prototype chain.
  • [[Prototype]] của các thuộc tính .prototype không liên quan gì đến các [[Prototype]] của chính bản thân các function điều này dẫn đến việc dù [[Prototype]] của function B có tham chiếu đến Function.prototype nhưng b.foobar() đã không được tìm thấy và trả về lỗi khi thực thi

3. Khi nào cần chú ý đến prototype chain?

  • Hiệu suất: Nếu prototype chain quá dài, việc tìm kiếm các thuộc tính hoặc phương thức trong chuỗi prototype có thể ảnh hưởng đến hiệu suất.
  • Ghi đè phương thức: Bạn có thể ghi đè phương thức trong chuỗi prototype. Tuy nhiên, hãy cẩn thận vì điều này có thể gây ra xung đột hoặc làm thay đổi hành vi không mong muốn.
  • Chia sẻ phương thức: Prototype là 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 đối tượng. Điều này giúp tiết kiệm bộ nhớ.

Kết luận

Hiểu về prototypeprototype chain là một trong những khái niệm cốt lõi của JavaScript. Nó 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 hiểu rõ cách hoạt động của prototype chain, bạn sẽ có thể viết mã JavaScript tối ưu và linh hoạt hơn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí