Prototype

Hướng đối tượng trong Javascript

Trong Javascript không thừa kế theo kiểu Class-inheritance như Java/C# mà thừa kế theo Prototypal-inheritance.

Khác nhau cơ bản là Java/C# có chia ra classobject là khác nhau. Còn đối với Javascript mọi thứ đều là object. Trong Java/C# thì class thừa kế class, còn đối với Javascript thì object thừa kế object.

Ví dụ đối tượng tiger thừa kế đối tượng animal qua [[Prototype]]] bởi thuộc tính __proto__.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let animal = {
  eats: "I can eat"
};
let tiger = {
  jumps: "I can jump"
};

tiger.__proto__ = animal;
// tương đương Object.setPrototypeOf(tiger, animal);

console.log(tiger.eats); // I can eat

Thuộc tính __proto__ không phải là chuẩn của Javascript, mà nó được hầu hết các engine hổ trợ. Nếu viết theo chuẩn hãy sử dụng hai hàm Object.getPrototypeOf/Object.setPrototypeOf.

Về mặt kỹ thuật, chúng tôi có thể set và get [[Prototype]]] bất cứ lúc nào. Nhưng thông thường, chúng ta chỉ thiết lập nó một lần vào thời điểm tạo đối tượng và không sửa đổi nó nữa: tiger thừa kế từ animal và điều đó sẽ không thay đổi.

Và các engine JavaScript được tối ưu hóa cao cho việc này. Việc thay đổi prototype của chúng ta sẽ phá vỡ việc tối ưu của engine. Vậy nên chúng ta sẽ tránh ghi __proto__ khi cần thiết. Các ví dụ ở trang này việc ghi __proto__ chỉ để minh họa tính chất thừa kế trong JavaScript.

Khi thay đổi prototype chúng ta sẽ sử dụng thuộc tính prototype, cùng với toán tử new, hàm Object.create() chứ không sử dụng __proto__.

Object.prototype

Các object con thừa kế object cha và các object cha thừa kế từ object ông và cứ tiếp tục như vậy đến object trên cùng là Object prototype. Chúng ta gọi thừa kế như vậy là prototype chain.

Object.prototype là một đối tượng nằm trong đối tượng Object. Kiểu như thế này:

1
2
3
4
5
var Object = {
  prototype: {
    // cài đặc các hàm và thuộc tính trong prototype
  }
}

Ngoài Object.prototype được Javascript xây dựng sẵn, còn có các prototype tương tự như Array.prototype, String.prototype, Date.prototype. Tất cả prototype khác đều thừa kế từ Object.prototype.

Ví dụ:

1
2
3
4
5
6
7
8
var arr = [2, 4, 7];
console.log(arr.__proto__); // Array.prototype
console.log(arr.__proto__.__proto__); // Object prototype

var doubleArr = arr.map(a => a * 2);
console.log(doubleArr);

console.log(Array.prototype.map); // [Function map]

Hàm map không có trong arr mà nó sẽ thừa kế từ Array.prototype.map().