Cảm ơn bạn!
Tìm hiểu về Prototype trong JavaScript
Bài viết hôm nay, chúng ta sẽ tìm hiểu về khái niệm prototype trong JavaScript và cách hoạt động của nó nhé 😄😄.
Prototype trong JavaScript là gì?
Trong JavaScript, một object có thể kế thừa - inherit các đặc tính của object khác thông qua một thứ gọi là prototype. Mỗi object đều có thuộc tính của nó là prototype và bản thân prototype là một object.
Ví dụ:
let website = {name: 'homiedev'};
Khi ta in object website
này ra console. Bạn sẽ thấy object này có một thuộc tính gọi là prototype biểu thị bằng [[Prototype]]
.
Nguyên mẫu - prototype là một object và nó có các thuộc tính riêng của nó. Khi bạn lấy một thuộc tính của một object, nếu object có thuộc tính đó, nó sẽ trả về giá trị thuộc tính. Ví dụ:
console.log(website.name); // homiedev
JavaScript sẽ trả về giá trị của thuộc tính name
như mong đợi. Tuy nhiên, nếu ta thử truy cập một thuộc tính không tồn tại trong một object, JavaScript sẽ làm một công việc đó là tìm kiếm trong prototype của object.
Nếu JavaScript không tìm thấy thuộc tính trong prototype của object, nó sẽ tiếp tục tìm kiếm trong nguyên mẫu của prototype của object cho đến khi tìm thấy thuộc tính hoặc đến cuối prototype chain.
Đối tượng prototype cũng có prototype của chính nó và cứ tiếp tục như vậy cho đến khi nó gặp null
làm nguyên mẫu - prototype của nó. Vì vậy, những liên kết này được gọi là chuỗi nguyên mẫu - prototype chain. null
không có nguyên mẫu và nó có vai trò như một liên kết cuối cùng trong prototype chain.
Ví dụ: Chúng ta có thể gọi method toString()
của object website
như sau:
console.log(website.toString()); // '[object Object]'
Method toString()
return về một chuỗi biển thị object website
. Theo mặc định, nó trả về [object Object]
.
Khi hàm là giá trị của thuộc tính trong object thì nó được gọi là method.
Ở ví dụ này, khi chúng ta gọi method toString()
bằng object website
, JavaScript sẽ thử tìm nó trong object website
. Do object chúng ta tạo không có method toString()
, nên nó sẽ tiếp tục tìm kiếm method toString()
trong đối tượng prototype của object.
Chúng ta thấy trong prototype của website
có method toString()
, nên JavaScript sẽ sử dụng toString()
của prototype này.
Trong JavaScript có một hàm built-in là Object()
. Nếu sử dụng toán tử typeof
sẽ cho kết quả 'function'
.
console.log(typeof Object); // function
Các bạn chú ý là
Object()
là một hàm, chứ không phải là một object 😥😁.
Ngoài ra, JavaScript tạo ra một anonymous object - object ẩn danh và object này được tham chiếu qua thuộc tính prototype của hàm Object()
.
Mỗi function sẽ có một prototype object theo mặc định. Thuộc tính prototype của function có thể được truy cập bằng cách sử dụng <tên hàm>.prototype
console.log(Object.prototype);
object Object.prototype
có một số method hữu ích như toString()
và valueOf()
. Nó cũng có một thuộc tính quan trọng được gọi là constructor tạo tham chiếu đến hàm Object()
.
console.log(Object.prototype.constructor === Object); // true
Ví dụ để các bạn hình dung ^^:
Chúng ta sẽ định nghĩa một hàm khởi tạo - constructor function là Student
như bên dưới:
function Student(name) {
this.name = name;
}
Giống như hàm Object()
, hàm Student()
có một thuộc tính là prototype tham chiếu đến một anonymous object. Và anonymous object có thuộc tính constructor tạo tham chiếu đến hàm Student()
.
console.log(Student);
console.log(Student.prototype);
Ngoài ra, JavaScript liên kết object Student.prototype
với object Object.prototype
thông qua [[Prototype]]
, đây được gọi là liên kết nguyên mẫu.
Thêm method cho object prototype
Giả sử mình thêm một method sayHi
như sau:
function Student(name) {
this.name = name;
}
Student.prototype.sayHi = function() {
return "Xin chào, tên mình là " + this.name + " 😁";
}
Tiếp theo ta tạo một đối tượng mới:
const student1 = new Student('Hân');
console.log(student1); // {name: 'Hân'}
Sau đó gọi method sayHi
:
student1.sayHi(); // 'Xin chào, tên mình là Hân 😁'
Kết quả ta được như trên, dù sử dụng sayHi
từ object student1: {name: 'Hân'}
nhưng kết quả vẫn được in ra 🤨. Đó là do khi không tìm thấy method sayHi
, JavaScript đã đi theo liên kết nguyên mẫu và tìm thấy nó ở object Student.prototype
😁.
Bây giờ ta thử dùng method toString()
xem kết quả thế nào:
student1.toString(); // Kết quả: '[object Object]'
Như bạn thấy ở trên, ta vẫn in được kết quả ra, đó là vì khi không tìm thấy method toString()
trong object student1
, JavaScript theo liên kết nguyên mẫu và tìm đến Student.prototype
, tại đây nó cũng không tìm thấy. Nó tiếp tục theo liên kết nguyên mẫu và tìm đến object Object.prototype
. Tại đây nó tìm thấy method toString()
và sử dụng method này. Và chúng ta được kết quả như trên 😃😃.
Liên kết giữa student1
, Student.prototype
, Object.prototype
được gọi là prototype chain.
Nếu bạn gọi một method không tồn tại trên student1
, object Student.prototype
và object Object.prototype
, JavaScript thông báo lỗi vì nó không thể tìm thấy method bạn cần.
Ví dụ:
student1.xinNghiPhepHomNay(); // Báo lỗi
Truy xuất liên kết nguyên mẫu
Trong Object.prototype có một thuộc tính gọi là proto. Nó cho ta thấy được liên kết nguyên mẫu trong [[Prototype]]
của một object.
proto có thể không được dùng nữa vì nó sẽ được thay thế bằng Object.getPrototypeOf()
trong tương lai. Do đó, chúng ta không nên sử dụng proto trong quá trình viết chương trình.
student1.__proto__
trỏ đến object Student.prototype
.
console.log(student1.__proto__ === Student.prototype); // true
Như đã đề cập trước đó, bạn nên sử dụng Object.getPrototypeOf()
thay vì __proto__
.
Object.getPrototypeOf(student1) === Student.prototype // true
Chúng ta có thể xem prototype thông qua contructor của student1:
student1.constructor.prototype
student1.constructor
trả về function Student, do đó student1.constructor.prototype
trả về object Student.prototype
.
Như vậy thông qua bài này, mình xin tóm tắt những kiến thức chúng ta đã học trong bài:
- Object
Object.prototype
có thuộc tính constructor tham chiếu đến hàmObject
. - Mọi function đều có một object prototype. Object prototype này tham chiếu đến đối tượng
Object.prototype
thông qua liên kết[[Prototype]]
hay thuộc tính__proto__
. - Prototype chain cho phép một object sử dụng các method và thuộc tính của các object prototype của nó thông qua các liên kết
[[Prototype]]
. - Method
Object.getPrototypeOf()
trả về object prototype của một object. Sử dụngObject.getPrototypeOf()
thay vì__proto__
.