Prototype trong JavaScript
Bài đăng này đã không được cập nhật trong 6 năm
Ở thời kì thịnh hành ES6, Babel,... những từ khóa như Class
, constructors
, static
,... đều đã có trong JS nhưng thực sự OOP trong JS nó có thực sự giống như các ngôn ngữ OOP khác như Java hay PHP không?
Bài viết này, ta sẽ quay về thời ES5 trở về trước, lúc đó Prototype
đang xưng hùng xưng bá...
Tuy nhiên để câu chuyện trở nên mượt mà hơn, trước tiên, hãy nói chuyện về thằng Object
.
Nothing is true, Everything is Object
Trong JS, mọi thứ đều xoay quanh Object
.
Có những kiểu Number
, String
, Boolean
,... thậm chí cũng có thể chuyển sang dạng Object
(confused)
Và Class
ư, ví dụ viết một Class
bằng cú pháp ES6 nhé:
class Employee {
setName (name) {
this.name = name;
}
getName () {
return this.name;
}
setAge (age) {
this.age = age;
}
getAge () {
return this.age;
}
};
Cú pháp rất rõ ràng và chuẩn OOP đúng không? Nhưng thực ra bản chất của nó vẫn chỉ chỉ là một Object
=))
var employee = {
name: null,
age: null,
setName: function (name) {
this.name = name;
},
getName: function () {
return this.name;
},
setAge: function (age) {
this.age = age;
},
getAge: function () {
return this.age;
}
};
Ở đây điều mình muốn nói đến chính là JS cũng được coi là một ngôn ngữ OOP, tuy nhiên thay vì OOP dạng Class-based như JAVA hay PHP (Sử dụng Class
là khuôn mẫu cho các Object
và Class
có thể kế thừa từ Class
khác), thì JS được coi là ngôn ngữ OOP dạng Prototype-based (Prototype
là khuôn mẫu cho các Object
và Prototype
có thể kế thừa từ Prototype
khác).
Ơ tự nhiên đang Object
lại có Prototype
lạ lạ @@ Vậy Prototype
là gì (??)
Prototype
Mỗi Object
trong JS là một tập hợp các thuộc tính (property
) và trong số những thuộc tính đó có chứa 1 thằng được gọi là Prototype
.
Và không có gì thay đổi, Prototype
đó cũng là một Object
(facepalm) vì vậy nó cũng có Prototype
... Người ta gọi đó là một chuỗi Prototype
(Prototype chain). Chuỗi này là hữu hạn, cuối cùng của chuỗi
Prototype
đó là trùm cuối Object.Prototype
.
var viblo = {};
__proto__
ở trong hình chính là proptotype.
Đây có thể coi như 1 cách trình duyệt public ra để bạn truy cập vào
Prototype
củaObject
.
Kế thừa qua Prototype
Bài viết này đang hướng ngược lại thời kì trước đây, khi ES6 chưa xuất hiện hay những thư viện cồng kềnh chưa được sử dụng. Vì vậy việc kế thừa qua Prototype
là một vấn đề quan trọng khi nói JS là ngôn ngữ OOP.
Có thể hiểu Prototype
của Object
chính là khuôn mẫu, hay là sư phụ của Object
cho dễ hiểu.
Mỗi khi gọi đến một thuộc tính của thằng Object
để nhờ làm việc,JS sẽ tìm trong Object
xem có không, nếu không thì tìm đến thằng sư phụ.
Đấy là lí do mà có thể sử dụng những hàm như hasOwnProperty
để kiểm tra xem thuộc tính đó có tồn tại trong Object
hay không vì thằng sư tổ Object.prototype
đã có rồi.
var viblo = {};
viblo.hasOwnProperty('abc'); // false
Nếu thằng sư phụ hay sư tổ mà cũng không thể thực hiện được, lúc này việc cần làm là dạy cho 1 sư nào đó cách thực hiện để tất cả những đệ tử tầng dưới có thể làm theo =)) Ví dụ sư phụ chưa biết bay, ta sẽ cho sư phụ học bay, và các đệ tử tầng dưới được kế thừa lại những tinh hoa từ sư phụ:
// Sử dụng Object literal
var sensei = {
fly: function () {
console.log('Can Fly');
}
};
var senpai = {
__proto__: sensei
};
var kohai = {
__proto__: senpai
};
senpai.fly(); // Can Fly
kohai.fly(); // Can Fly
Hoặc:
// Sử dụng Constructor Function
var Sensei = function () {
this.fly = function () {
console.log('Can Fly');
};
return this;
};
var Senpai = function () {
//
};
Senpai.prototype = new Sensei();
var kohai = new Senpai();
kohai.fly(); // Can Fly
Khi tạo Object
bằng cách gọi new Senpai()
thì prototype
của kohai
là Senpai.prototype
. Và nếu muốn thêm function
cho các Object
đệ tử thì chỉ cần thêm 1 lần vào prototype
là được.
Sensei.prototype.fight = function () {
console.log('Can Fight');
}
var kohai = new Sensei();
kohai.fight(); // Can Fight
Tuy nhiên nếu tự dưng có thằng đệ tử do được bố mẹ năn nỉ xin cho học nhưng thấy nó tư chất si đa không muốn dạy cho một thân bản lãnh thì lúc đấy đành bí mật phong bế nó trước vậy =))
var phevat = Object.create(null);
Sensei.prototype.taichi = function() {
console.log('Can Taichi');
}
phevat.taichi(); // TypeError: phevat.taichi is not a function
Ý nghĩa của Prototype
Từ phiên bản ES5 trở về trước, JS không hề có khái niệm Class
, vấn đề này mình có đá qua vài lần ở trên kia rồi, vậy nên việc kế thừa giống các ngôn ngữ OOP khác trong JS cũng không thể thực hiện được như bình thường. Và Prototype
là người hùng giúp ta có thể thực hiện được việc kế thừa.
Vậy nên mới nói việc kế thừa của JS là Prototype-based
, còn trong các ngôn ngữ OOP khác là Class-based
.
Kết luận
Tất cả những kiến thức trên thực ra áp dụng vào thời điểm này có vẻ hơi ít vì sự mạnh mẽ của ES6 và Babel, tuy nhiên mình thực sự mong qua bài viết này khi sử dụng OOP trong JS bạn sẽ hiểu thêm được phần nào cách hoạt động và sự hơi liên quan với OOP trong các ngôn ngữ khác. Cám ơn đã theo dõi!
Tham khảo:
https://viblo.asia/p/object-oriented-programming-in-javascript-its-really-about-object-DXOGRZdBGdZ
https://viblo.asia/p/javascript-prototype-ByEZk9Wx5Q0
https://toidicodedao.com/2016/02/02/series-javascript-sida-po-ro-to-tai-prototype-la-cai-gi/
All rights reserved