Prototype chain trong Javascript

prototye chain

# Prototype là gì? có ăn được không?

Javascript được gọi là prototype-based language. Lâu rồi mình đọc đâu đó thì nói là ngôn ngữ “Nhái” hướng đối tượng. Tức Javascript hỗ trợ xây dựng một số tính chất của OOP thông qua kỹ thuật Prototype của nó. Cụ thể Javascript xây dựng tính chất kế thừa (Inheritance) dựa trên Prototype. Mình sẽ tìm hiểu kỹ hơn Prototype là như thế nào nhé.

Prototype (Khuôn mẫu) – Nôm na có một Object cha có định nghĩa các Property và Method. Giờ đối tượng tiếp theo muốn kế thừa những thuộc tính này thì làm thế nào? Javascript chế ra prototype, _proto_ trỏ tới mấy cái object này, để xài ké lại những method, property của nó.

function Person(first, last, age, gender, interests) {
   // property and method definitions
   this.first = first;
   this.last = last;
   this.study = function() {
      console.log("study something");
   }
}

Person.prototype.relax = function() {
   console.log('do blabla');
}

var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
Object.getPrototypeOf(person1) === person1.__proto__ //true
Object.getPrototypeOf(person1) === Person.prototype //true
person1.__proto__ === Person.prototype //true
person1.constructor === Person //true
person1.__proto__.__proto__ === Object.prototype //true
Person.prototype.__proto__ === Object.prototype //true
Object.prototype.__proto__ === null //true

Trong ví dụ trên, mình tạo ra một Contructor Function để tạo ra các đối tượng (Instance) thuộc dòng/loại Person. Đối tượng person1 là instance được tạo bởi hàm khởi tạo trên.
javascript prototype example

Sau đó mình kiểm tra lại các property và method mà đối tượng person1. Như hình trên thì các bạn có thể thấy chúng bao gồm:
– Thuộc tính định nghĩa trong Person’s Constructor: first, last
– Các method định nghĩa bên trong Constructor: study
– Các method định nghĩa theo Person’s prototype: relax
– Các method lạ lạ, mình xài ké từ đâu đó ^^: hasOwnProperty, toString,…

Như các bạn thấy ở trên, person1 tạo ra đã được kế thừa, xài lại một số method từ Object.prototype. Prototype là gì? Prototype là kỹ thuật để Javascript kế thừa những property và method từ một đối tượng khác. Để làm được chuyện này, nó đã làm những việc sau:
– Khi định Person Constructor. Trong javascript thì nó function cũng là một object.
– Khi gọi person1 = new Person(…). Mối đối tượng mới được tạo ra, có đặc điểm.
+ Có thuộc tính constructor tham chiếu tới Person Constructor ban đầu.
+ Có thuộc tính __proto__ tham chiếu tới Person.prototype
+ Person.prototype.__proto__ trỏ tới Object.prototype. Một constructor tạo ra thì mặc định prototype của nó sẽ trỏ về Object.prototype. Đó là lý do mới tạo ra các đối tượng đã được xài ké mấy method từ Object.
– Object.prototype là chốt chặn cuối cùng, nó không kế thừa từ ai nữa: Object.prototype.__proto__ === null

Tiếp theo mình sẽ nói rõ hơn khi gọi tới method thì Javascript sẽ làm thể nào để kiếm ra cái method đó và thực thi.

# Prototype chain?

– person1.__proto__ trỏ tới Person.prototype
– person1.__proto__.__proto__ === Person.prototype.__proto__ === Object.prototype

Khi thực thi bản thân person1 không khởi tạo luôn method luôn trên đối tượng mà chỉ sử dụng một thuộc tính __proto__ để lưu trữ nơi mà mình sẽ xài lại. Tương tự cái nơi mà nó xài lại, nó lại tham chiếu tới một chỗ khác. Cụ thể
– person1 xài ké Person.prototype.
– Person xài ké từ Object.
– Giả sử sau mình muốn làm một Class Student đi. Thì student lại xài ké thằng gần nhất là Person.

Prototype chain là cơ chế để Javascript duyệt lại qua các cấp kế thừa thông qua __proto__ để tìm kiếm property và method được sử dụng. Tiếp theo mình sẽ nói cụ thể hơn khi gọi các property và method trên person1 thì Javascript sẽ tìm kiếm như thế nào.

## Thuộc tính và phương thức trong constructor.

person1.study()
person1.first
– Bước 1, kiểm tra trong constructor có hay không.
– Yes: Tìm thấy, xài thôi, dừng ở đây

## Thuộc tính và phương thức trên Prototype của Constructor.

person1.relax()
– Bước 1, kiểm tra trong constructor có hay không.
– No, Bước 2: Tìm tiếp trong __proto__
– Yes: Tìm thấy, xài thôi, dừng ở đây.

## Thuộc tính và phương thức trên Object.Prototype.

person1.toString()
– Bước 1, kiểm tra trong constructor có hay không.
– No, Bước 2: Tìm tiếp trong __proto__
– No, Bước 3: Tìm tiếp trong __proto__.__proto__ (Tức là person1.__proto__.__proto__, tương đương Person.prototype.__proto__)
– Yes, Thấy rồi

## Thuộc tính và phương thức không tồn tại

person1.blabla() //undefined
– Bước 1, kiểm tra trong constructor có hay không.
– No, Bước 2: Tìm tiếp trong __proto__
– No, Bước 3: Tìm tiếp trong __proto__.__proto__ (Tức là person1.__proto__.__proto__, tương đương Person.prototype.__proto__, Tương đương Object.prototype)
– No, Bước 4: Tìm tiếp trong Object.prototype.__proto__ (null).
– No, Tìm hết trong Prototype Chain rồi mà không thấy. Thôi dừng, trả về undefined.

# Sử dụng Prototype để thiết kế theo hướng OOP.

Tiếp theo mình sẽ sử dụng Prototype để viết một Class mới Student, kế thừa những gì đã có từ Person.

function Person(first, last, age, gender, interests) {  
  // property and method definitions
  this.first = first;
  this.last = last;
  this.study = function() {
    console.log("study something");
  }
}

Person.prototype.relax = function() {
   console.log('do blabla');
}

Person.prototype.getName = function() {
   return this.first + " " + this.last
}


function Student(first, last, age, gender, interests, school) {
   this.first = first
   this.last = last
   this.school = school
}

Student.prototype = new Person()

Student.prototype.goToSchool = function() {
   return "go to " + this.school
}

var student1 = new Student('Bob', 'Smith', 32, 'male', ['music', 'skiing'], 'VietNam');


Nhìn hình trên các bạn có thể thấy, Student đã được kế thưà method getName từ Person. Và một số thực sau:
– student1.__proto__ === Student.prototype
– student1.__proto__.__proto__ === Person.prototype === Student.prototype.__proto__

Nguồn tham khảo:
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes

Leave A Reply

Your email address will not be published. Required fields are marked *