Xin chào, hôm nay mình sẽ giới thiệu về Prototype trong JavaSCript. Nó là thứ cơ bản nhất của JavaScript. Cùng theo dõi bài viết với mình nhé.
1. Ngôn ngữ dựa trên Prototype là gì?
Chúng ta thừa nhận rằng JavaSript là một ngôn ngữ dựa trên nguyên mẫu (prototype-base), nó có cung cấp tính kế thừa, các đối tượng có thể có một đối tượng nguyên mẫu, hoạt động như một đối tượng mẫu mà nó kế thừa các phương thức và thuộc tính.
Đối tượng nguyên mẫu của một đối tượng cũng có thể có một đối tượng nguyên mẫu, đối tượng này kế thừa các phương thức và thuộc tính từ đó,…
> Ý là: Trên bố có thể vẫn còn Ông nội đó. Cháu thì vẫn thừa kế được từ ông...
Điều này thường được gọi là chuỗi nguyên mẫu (Prototype chain) và cũng nhằm giải thích tại sao các đối tượng khác nhau có thuộc tính và phương thức xác định trên các đối tượng khác có sẵn cho chúng.
2. Tìm hiểu về các đối tượng nguyên mẫu
Nguyên mẫu (Prototype) là một đối tượng được liên kết với mọi hàm và đối tượng theo mặc định trong JavaScript, trong đó thuộc tính nguyên mẫu của hàm có thể truy cập và sửa đổi được và thuộc tính nguyên mẫu của đối tượng (hay còn gọi là thuộc tính) không hiển thị.
Mọi hàm đều bao gồm đối tượng nguyên mẫu theo mặc định.
Đối tượng nguyên mẫu là loại đối tượng có thể liệt kê đặc biệt mà các thuộc tính bổ sung có thể được gắn vào nó.
Đối tượng này sẽ đươc chia sẻ trên tất cả các phiên bản của hàm khởi tạo của nó.
Cùng xem ví dụ bên dưới nhé:
function Student() {
this.name = 'Trung';
this.gender = 'Male';
}
Student.prototype.age = 15;
var stu_Obj1 = new Student();
console.log(stu_Obj1.age); // 15
var stu_Obj2 = new Student();
console.log(stu_Obj2.age); // 15
Qua đó chúng ta thấy mọi đối tượng tạo bằng hàm khởi tạo với từ khóa new
, bao gồm thuộc tính __proto__property
trỏ đến đối tượng nguyên mẫu của hàm đã tạo ra đối tượng này.
Bạn có thể xem thuộc tính nguyên mẫu của đối tượng hoặc hàm trong công cụ dành cho nhà phát triển của chrome hoặc firefox (F12).
Ví dụ:
function Student() {
this.name = 'Trung';
this.gender = 'Male';
}
var stu_Obj = new Student();
console.log(Student.prototype); // object
console.log(stu_Obj.prototype); // undefined
console.log(stu_Obj.__proto__); // object
console.log(typeof Student.prototype); // object
console.log(typeof stu_Obj.__proto__); // object
console.log(Student.prototype === stu_Obj.__proto__); // true
Nhúng đoạn JS trên vào HTML và chạy file trên trình duyệt.
Nhấn F12 để mở phần debugging trong chrome nè:
Trong ví dụ trên, thuộc tính nguyên mẫu của Hàm có thể được truy cập đến bằng cách sử dụng <functions_name>.prototype
. Tuy nhiên, một đối tượng (Object) không hiển thị thuộc tính nguyên mẫu, thay vào đó bạn có thể truy cập nó bằng __proto__
> Lưu ý: Thuộc tính nguyên mẫu là loại đối tượng có thể liệt kê đặc biệt, không thể lặp lại bằng cách sử dụng vòng lặp for-in hoặc foreach
3. Nguyên mẫu của đối tượng (Object’s Prototype)
Thuộc tính nguyên mẫu của đối tượng là vô hình, do đó sử dụng phương thức Object.getPrototypeOf(obj)
thay vì __proto__
để truy cập đối tượng nguyên mẫu.
function Student() {
this.name = 'Trung';
this.gender = 'Male';
}
var studObj = new Student();
Student.prototype.sayHi = function() {
alert('Hi');
}
var stu_Obj1 = new Student();
var proto = Object.getPrototypeOf(stu_Obj1) // trả về Student's prototype object
alert(proto.constructor); // trả về Student function
Kết quả:
Đối tượng nguyên mẫu bao gồm các thuộc tính và phương thức bên dưới.
Thuộc tính:
-
constructor
: Trả về hàm tạo một instance.
-
__proto__
: Đây là một thuộc tính vô hình của đối tượng. Nó trả về đối tượng nguyên mẫu của một hàm mà nó liên kết đến
Phương thức:
-
hasOwnProperty()
: Hàm này trả về một boolean
cho biết liệu một đối tượng có chứa thuộc tính được chỉ định là thuộc tính trực tiếp của đối tượng đó và không được kế thừa thông qua chuỗi nguyên mẫu hay không.
-
isPrototypeOf()
: Hàm này trả về một chỉ báo boolean là liệu đối tượng được chỉ định có nằm trong chuỗi nguyên mẫu của đối tượng mà phương thức này được gọi hay không.
-
propertyIsEnumerable()
: Hàm này thì trả về một boolean cho biết thuộc tính được chỉ định có thể liệt kê được hay không.
-
toLocaleString()
: Hàm này trả về chuỗi ở định dạng cục bộ.
-
toString()
: Trả về một chuỗi
-
valueOf()
: Hàm này thì trả về giá trị ban đầu của đối tượng đươc chỉ định
4. Thay đổi nguyên mẫu
Nguyên mẫu của đối tượng được liên kết với đối tượng nguyên mẫu của hàm. Nếu bạn thay đổi nguyên mẫu của hàm thì chỉ các đối tượng mới sẽ được liên kết với nguyên mẫu đã thay đổi.
Tất cả các đối tượng hiện có khác sẽ vẫn liên kết với nguyên mẫu cũ của hàm.
Ví dụ:
function Student() {
this.name = 'Trung';
this.gender = 'Male';
}
Student.prototype.age = 15;
var stu_Obj1 = new Student();
console.log('stu_Obj1.age = ' + stu_Obj1.age); // 15
var stu_Obj2 = new Student();
console.log('stu_Obj2.age = ' + stu_Obj2.age); // 15
Student.prototype = { age: 20 }
var stu_Obj3 = new Student();
console.log('stu_Obj3.age = ' + stu_Obj3.age); // 20
console.log('stu_Obj1.age = ' + stu_Obj1.age); // 15
console.log('stu_Obj2.age = ' + stu_Obj2.age); // 15
Kết quả:
5. Sử dụng nguyên mẫu
Đối tượng nguyên mẫu đang được JavaScript engine sử dung cho hai việc sau:
-
Tìm các thuộc tính và phương thức của một đối tượng.
-
Triển khai việc kế thừa trong JavaScript (Class mình sẽ nói về điều này).
function Student() {
this.name = 'Trung';
this.gender = 'Male';
}
Student.prototype.sayHi = function() {
alert("Hi");
};
var stu_Obj = new Student();
stu_Obj.toString();
Trong ví dụ trên, phương thức toString()
không được định nghĩa trong Student
, vậy sao nó tìm thấy đươc toString()
và sử dụng nó?
* Hãy xem nguyên mẫu như trong hình bên dưới.
Đầu tiên, JavaScript engine sẽ kiểm tra xem phương thức toString()
có được gắn vào stu_Obj
hay không? (có thể đính kèm một hàm mới vào một thể hiện trong JavaScript).
Nếu nó không tìm thấy ở đó thì nó sử dụng liên kết __proto__
của stu_Obj
trỏ đến đối tượng nguyên mẫu của các hàm trong Student
.
Nếu nó vẫn không thể tìm thấy nó ở đó thì nó sẽ đi lên trong hệ thống và kiểm tra đối tượng nguyên mẫu của các hàm trong Object bởi vì tất cả các đối tượng đều có nguồn gốc từ Object trong JavaScript và tìm phương thức toString()
.
Do đó, nó tìm thấy phương thức toString()
trong đối tượng nguyên mẫu của hàm Object và vì vậy chúng ta có thể gọi stu_Obj.toString()
.
Theo cách này, nguyên mẫu rất hữu ích khi chỉ giữ một bản sao của các hàm cho tất cả các đối tượng (cá thể).
Tổng kết
Như vậy mình vừa giới thiệu các bạn một chút về nguyên mẫu trong JavaScript. Phần này có lẽ là hơi trừu tượng. Nhưng đừng lo, qua bài học về class sau đây thì bạn sẽ hiểu ra mà thôi.
Hẹn gặp lại bạn ở bài học tiếp theo nhé.
> Đọc thêm về Prototype trên Mozilla