在JavaScript中,prototype對象是實現物件導向的一個重要機制。每個函數就是一個對象(Function),函數對象都有一個子物件prototype對象,類是以函數的形式來定義的。prototype表示該函數的原型,也表示一個類的成員的集合。在通過new建立一個類的執行個體對象的時候,prototype對象的成員都成為執行個體化對象的成員。
1、該對象被類所引用,只有函數對象才可引用;
2、在new執行個體化後,其成員被執行個體化,執行個體對象方可調用。
同時,函數是一個對象,函數對象若直接聲明成員,不用被執行個體化即可調用。
第一。先看如下函數
Js代碼
- function createPerson(name,sex,birthday) {
- //通過參數傳遞賦予函數對象值
- this.name = name ;
- this.sex = sex;
- this.birthday = birthday;
- this.sayHi = function(){
- alert(this.name+"is saying hello to everyone.");
- };
- return this;
- }
上面函數通過定義Function類createPerson來建立一個人,並賦予人的姓名,性別,生日和說話的屬性,切記,在JS中,這不同於其他的物件導向程式設計語言的地方,JS是沒有方法這一說法。
然後,我們來建立一個人名叫Rose,定義如下
var rose = new createPerson('Rose ','female','1985-01-01');
這樣子,我們就可以直接通過rose對象去直接存取rose具有的屬性了。如rose.name,rose.sex,對於sayHi,相對特殊,因為 rose的sayHi是一個函數,所以對於sayHi的調用,就像一般的函數調用一樣,rose.sayHi();
可能你會覺得,這樣子寫不是好完美了嗎?的確,如果在其他物件導向程式設計語言中,類似於這樣子的寫法的確是完美了,但是對於JS卻有一個重要的特性,就是原型。要理解原型,還得從分析var rose = new createPerson('Rose ','female','1985-01-01');這代碼入手。這段代碼執行過程大概如下,
第一步是建立一個新對象-rose
第二步將該對象內建的原型對象設定為建構函式prototype引用的那個原型對象,也就是因為JS每個函數,都具有原型對象如(createPeson.prototype)。這就是說rose對象的原型對象設定為建構函式createPeson.prototype
第三步就是將該對象作為this參數調用建構函式,完成成員設定等初始化工作。
換句話說就是
Js代碼
- functon createPerson(name,sex,birthday) {
-
- this.name = name ;
- this.sex = sex;
- this.birthday = birthday;
- this.sayHi = function(){
- alert(this.name+"is saying hello to everyone.");
- };
- return this;
- } 被替換成如下的調用形式,
-
- functon createPerson(name,sex,birthday) {
-
- rose.name = name ;
- rose.sex = sex;
- rose.birthday = birthday;
- rose.sayHi = function(){
- alert(rose.name+" is saying hello to everyone.");
- };
- return rose;
- }
對象在通過上述三個階段建立後,對象上的任何訪問和操作都只與對象自身及其原型鏈上的那串對象有關,與建構函式再扯不上關係了。換句話說,建構函式只是在建立對象時起到介紹原型對象和初始化對象兩個作用。
我們再深入想想,如果我們要建立1000個rose這樣子的對象,上述的三個階段是不是要執行1000次呢?答案是。這樣子就太消耗效能,那有什麼方法解決呢。就是通過prototype來最佳化了,最佳化後的代碼如下
------------------------------------------------------------------------
Js代碼
- functon createPerson(name,sex,birthday) {
-
- this.name = name ;
- this.sex = sex;
- this.birthday = birthday;
- return this;
- }
-
- createPerson.prototype.sayHi = function(){
- alert(this.name+" is saying hello to everyone.");
- };
------------------------------------------------------------------------
上述代碼,在啟動並執行過程中就賦予了createPerson對象具有sayHi屬性,而不是在建構函式中再進行初始化設定,無疑是對效能的一個質的提升。
然後通過
var rose = new createPerson('Rose','female','1985-01-01');
var lily = new createPerson('Lily ','female','1985-01-01');
rose.sayHi();
lily.sayHi();
//輸出的結果是
Rose is saying hello to everyone.
Lily is saying hello to everyone.
啟動並執行結果正是我們想得到的結果。但這時可能你有疑問了,如果,函數對象和函數原型對象都同時具有sayHi方法,這時結果會怎麼樣子呢?還是先看如下代碼
Js代碼
- function createPerson(name,sex,birthday,canSay) {
- this.name = name ;
- this.sex = sex;
- this.birthday = birthday;
- if(canSay) {
- this.sayHi = function(){
- alert(this.name+"is saying hello to everyone.");
- };
- }
- return this;
- }
- createPerson.prototype.sayHi = function(){
- alert(" Somebody is saying hello to everyone.");
- };
-
- var rose = new createPerson('Rose','female','1985-01-01',true);
- var lily = new createPerson('啞吧','female','1985-01-01',false);
- rose.sayHi();
- lily.sayHi();
//啟動並執行結果是
Rose is saying hello to everyone.
Somebody is saying hello to everyone.
怎麼去理解運行結果呢?原來JS對象,在尋找自身屬性的時候,會先從對象的內建對象鏈尋找是否存在該屬性。因此不難理解 rose.sayHi() 的運行結果:Rose is saying hello to everyone.但是對於lily.sayHi();的運行結果又是怎麼回事呢?原來JS對象先從對象的內建對象鏈尋找是否存在該屬性,尋找到則返回,如果尋找不到,再去對象原型鏈尋找,可見lily對象會從createPerson.prototype.sayHi = function(){
alert(" Somebody is saying hello to everyone.");
};原型鏈中尋找返回然後再調用sayHi方法,因而得到的結果就是 Somebody is saying hello to everyone