Tìm hiểu javascript prototype

Lời mở đầu

Với mục đích của bài viết này, tôi sẽ nói về Javascript prototype trong ES5. Như mọi người đã biết trong ES5 javascript không có khái niệm class, nên cũng sẽ không có khái niệm kế thừa như các ngôn ngữ lập trình khác như Java, C#, PHP ... . Chính vì vậy prototype đã được tạo với mục đích giúp chúng ta có thể kế thừa thuộc tính hay phương thức. Khái niệm Object tôi muốn đề cập sau đấy cũng giống như class trong ngôn ngữ lập Java, C#, PHP ...

Prototype

Mọi Object trong JS đều có prototype. Bản thân prototype cũng là một Object. Tất cả Object đều kế thừa thuộc tính và phương thức từ prototype. Tất cả các JS Object (Date, Array, RegExp, Function, ....) kế thừa từ Object.prototype.

  • Ở hình vẽ trên mọi người hãy hình dung obj chính là Object. Còn proto chính là prototype.obj2 là một Object nào đó kế thừa từ Object.prototype. Như mình đã nói ở trên là mọi object đều kế thừa từ object.prototype. Và các Object kế thừa trỏ đến đến Object.prototype tức là khi chúng ta thêm hay bớt thuộc tính thì những Object kế thừa cũng thay đổi như vậy. Ví dụ dưới đây mình sẽ thêm thuộc tính name giá trị kiên vào Object.prototype.
  • Sau đó mình sẽ in ra String.prototype để xem nó có kế thừa những gì từ Object.prototype không nhé ! proto' ở đấy là một thuộc tính của String trỏ đến Object.prototype mà nó kế thừa. Mọi người thử in ra tương tự với Number, Date ... cũng sẽ nhận được kết quả tương tự. Ngoài việc kế thừa thì bạn cũng có thể thêm thuộc tính và phương thức vào String Object, hoặc định nghĩa lại một phương thức nào đó mà String đã định nghĩa. Vấn đề này mình sẽ trình bày kĩ hơn ở phần dưới đây.

Tạo Object

Trong javascript Object là cặp keys và value ví dụ chúng ta muốn mô tả tên ai đó. Bạn có thể có một Object gồm 2 từ khóa Firstname giá trị là Bach và Lastname giá trị là Kien. Keys trong Javascript Object là một String. Tất cả object được tạo với Object literal và với Object constructor kế thừa từ Object.prototype. Vì vậy, Object.prototype là thuộc tính nguyên mẫu của tất cả các đối tượng đã tượng đã được tạo với new Object() hoặc {}. Do đó chúng đều có các hàm như constructor, hasOwnProperty, toString thuộc về của Object.prototype. Tạo bằng Object literal :

var Person = {
    firstname :  'Bach',
    lastname : 'Kien',
    getName : function() {
        console.log(this.firstname + ' ' + this.lastname);
    }
}

Person.firstname //Bach
  • Điều quan trọng nhất việc mở rộng thuộc tính và phương thức là Object literal đó luôn đặt một Object's prototype khi một đối tượng mới được khởi tạo nó được đặt ở Object.prototype. Bên trong Object literal giống như thế này :
  • Mặc định Object.prototype mặc định đi kèm với một số method mà chúng ta mong đợi object chứa, và thông qua sự kì diệu của chuỗi prototype, tất cả các đối tượng được tạo ra như Object literal sẽ chứa những thuộc tính. Tất nhiên các đối tượng có thể an toàn ghi đè chúng bằng cách xác định các thuộc tính trực. Thông thường các developer sẽ ghi đè toString method :
var alex = { firstName: "Alex", lastName: "Russell" };

alex.toString() // "[object Object]"

var brendan = {  
  firstName: "Brendan",
  lastName: "Eich",
  toString: function() { return "Brendan Eich"; }
};

brendan.toString() // "Brendan Eich"  
  • Điều này đặc biệt hữu ích vì khi chúng ta muốn định nghĩa lại một phương thức mà được javascript cung cấp.

Tạo bằng new Object

  • Cũng giống như Object literal , khi ta tạo mới một đối tượng bằng new Object thì đồng thời javascript cũng khởi tạo cho chúng ta Object.prototype.
  • Đến bây giờ , bạn cần hiểu rõ rằng prototype sử dụng để kế thừa chức nằng, giống như ngôn ngữ lập trình hướng đổi tượng truyền thống, để tạo thuận lợi cho việc sử dụng theo cách này,javascript cung cấp toán tử new.
  • Để thuận lợi cho việc lập trình hướng đối tượng Javascript cho phép bạn sử dụng một Object Function kết hợp với prototype để sử dụng cho đối tượng mới và một constructor function để gọi :
var Person = function(firstName, lastName) {  
  this.firstName = firstName;
  this.lastName = lastName;
}

Person.prototype = {  
  toString: function() { return this.firstName + ' ' + this.lastName; }
}
  • Javascript cung cấp toán tử new giúp chúng ta quen thuộc với lập trình hướng đối tượng truyền thống.
var mark = new Person("Kien", "Bach");  
mark.toString() // "Kien Bach"  

Kế thừa, gán phương thức và thuộc tính dựa trên prototype

Prototype rất quan trọng trong javascript vì js không có sự kế thừa cổ điển dựa trên các class (hầu hết các ngôn ngữ lập trình hướng đối tượng có). Và do đó sự kế thừa trong javascript được thực hiện thông qua prototype. Kế thừa là một mô hình trong đó các đối tượng có thể kế thừa thuộc tính và phương thức từ lơp Cha.


function Fruit(){
this.name = 'Apple';
}

//thêm thuộc tính color = Red vào fruit prototype 
Fruit.prototype.color = 'Red';
//Thêm method getNameAndColor vào Fruit prototype property
Fruit.prototype.getNameAndColor = function() {
console.log(this.name + '  ' + this.color);
}
var newObj = new Fruit();
console.log(Fruit.getNameAndColor());// Appple Red


var person = {
    firstname : 'Default', 
    lastname : 'Default',
    getFullName : function() {
        console.log(this.firstname + ' ' + this.lastname);
     }
}
 
var Rooney = {
    //
}

Rooney.__proto__ = person;
// Lúc này roney sẽ kế thuộc tính  lastname và getFullName function của person
console.log(Rooney.lastname); // Default
  • Object Constructor Fuit đã thêm getNameAndColor vào function như một method, sau đó khi khởi tạo đối tượng bằng từ khóa new lúc này method đã được thêm vào lên ta có thể gọi getNameAndColor .
  • Object literal Rooney kế thừa thuộc tính và phương thức từ Person, nhưng mọi người chú ý Rooney sẽ không kế thừa firstname của Person vì trong Object Rooney đã có firstname.

Kết luận

Đơn giản prototype có phần giống class , được sử dụng để kế thừa trong javascript !

Tài liệu tham khảo

All Rights Reserved