Một câu hỏi sẽ được đặt ra là cơ chế hoạt động của prototype như thế nào? Tại sao với prototype ta có thể giả lập khá nhiều các đặc tính hướng đối tượng? Thật ra prototype lại có một cơ chế hoạt động khá đơn giản: Mỗi khi bạn thực hiện thao tác với thuộc tính và phương thức của một đối tượng nào đó trong JavaScript, thì trình thông dịch sẽ thực hiện các bước tuần tự sau để xác định thuộc tính hay phương thức nào được thực thi:
Nếu thuộc tính hay phương thức của đối tượng đang xét có giá trị hoặc đã được gán giá trị thì thuộc tính hay phương thức đó được sử dụng.
Nếu không thì kiểm tra giá trị của thuộc tính của prototype trong cấu trúc của object.
Cứ tiếp tục như vậy cho đến khi tìm thấy thuộc tính phù hợp (thuộc tính đã được gán giá trị) hoặc giá trị tìm được là kiểu Object.
Chính vì vậy bất cứ khi nào muốn thêm một thuộc tính hay gắn thêm một phương thức mới cho một object bất kỳ ta chỉ việc khai báo nó như là thuộc tính của prototype.
Để thấy rõ hơn điều này ta sẽ cùng nhau tìm hiểu sâu hơn một chút về các thuộc tính và phương thức của các đối tượng cài đặt sẵn bên trong JavaScript là Object và Function
a) Object: Thuộc tính: constructor prototype Phương thưc: hasOwnProperty() isPrototypeOf() toString() valueOf() toLocaleString()
Ở đây chúng ta chỉ cần lưu ý phương thức khá đặc biệt đó là hasOwnProperty();
Với hasOwnProperty() sẽ trả về giá trị true nếu object đang xét có thuộc tính nào đó nhưng không phải là thuộc tính được khai báo kiểu mở rộng prototype, ví dụ:
var myObj=new Object(); myObj.firstProperty="xyz"; myObj.prototype.secondProperty="abc"; alert(myObj.hasOwnProperty("firstProperty")) //true alert(myObj.hasOwnProperty("fdasffsdf")) //false alert(myObj.hasOwnProperty("secondProperty")) //false b) Function Thuộc tính: constructor prototype arguments arity caller length Phương thức: apply() call() toString() valueOf()
Với đối tượng Function, chúng ta sẽ tìm hiểu kĩ hơn một chút bởi lẽ đây là đối tượng chính dùng trong lập trình OOP với JavaScript.
Thuộc tính constructor: thuộc tính này trả về một constructor mà từ đó object được tạo ra, ví dụ:
alert(myFunc.constructor); // kết quả sẽ là Function
Lưu ý rằng thuộc tính này chỉ có trong các biến có kiểu object, nên với một biến bất kỳ muốn sử dụng constructor thì ta phải kiểm tra kiểu trước khi sử dụng, ví dụ.
if(typeof myVar =="object"){ alert(myVar.constructor); }
Thuộc tính arguments: arguments thực chất là một mảng chứa các tham số cho function, khi
function được gán cho một đối số thì đối số này sẽ được đẩy vào mảng arguments, ta xét ví dụ sau: function test(){ var arg=test.arguments; for(var i=0;i alert(arg[i]); } }
test(1,"a");// sẽ đưa ra giá trị 1 và sau đó là "a"
Để ý rằng hàm test ban đầu không khai báo tham số, nhưng khi chạy ta đã thêm hai tham số vào cho nó do vậy trong arguments sẽ có 2 giá trị.
Phương thức call() và apply(): Đây là hai phương thức của object Function, dùng để thực thi, hoặc
gọi một function. Tham số đầu của hai phương thức trên thường là một object, cái mà sẽ được coi là object hiện thời và là tham số cho hàm thực thi phương thức call() hay apply(). Trong thực tế người ta thường dùng call thay cho apply bởi chức năng không có gì khác nhau, chỉ khác ở tham số truyền vào cho hai phương thức. Để minh họa điều này ta xét ví dụ sau:
function showInfo(){ alert(this.name); }
function myObject(name){ this.name=name;
this.show=showInfo; }
var myObj=new myObject("AxitDN"); //Cách thông thường
myObj.show(); //kết quả cho AxitDN //Sử dụng call
showInfo.call(myObj); //kết quả cho AxitDN
Ví dụ trên cho ta thấy rằng trong JavaScript, các hàm được sử dụng một cách khá tự do, thậm trí được sử dụng với một mục đích hoàn toàn khác so với lúc nó được tạo cho đến khi kết thúc chương trình. Không những thế với thuộc tính đặc biệt prototype càng làm cho chương trình viết bằng JavaScript trở nên vô cùng sinh động.