JavaScript 面向?qū)ο缶幊蹋?) 定義類
更新時間:2010年05月18日 01:15:57 作者:
最近這一段時間事情太多了,沒有時間再繼續(xù)寫,幸好這兩天有點小閑,先小寫一下JavaScript中面向?qū)ο笠恢型扑]的方法。
本文承接上一篇JavaScript面向?qū)ο缶幊蹋?) 基礎。
上篇說過,JavaScript沒有類的概念,需要通過函數(shù)來實現(xiàn)類的定義。先通過一個例子說明:
function myClass()
{
var id = 1;
var name = "johnson";
//properties
this.ID = id;
this.Name = name;
//method
this.showMessage = function()
{
alert("ID: " + this.ID + ", Name: " + this.Name);
}
}
var obj1 = new myClass();
var obj2 = new myClass();
function的定義實際上相當于類的構(gòu)造函數(shù),最后兩句是創(chuàng)建這個類的實例。先分析第一句:var obj1 = new myClass(); 當用new創(chuàng)建類的實例時,解釋器首先會創(chuàng)建一個空的對象。然后運行這個myClass函數(shù),并將this指針指向這個類的實例。當碰到this.ID = id;和this.Name = name;及this.showMessage = function(){...}時,便會創(chuàng)建這兩個屬性,和這個方法,并把變量id,name的值一級函數(shù)的定義賦給這兩個屬性及這個函數(shù)對象(shwoMessage)。這個過程相當于初始化這個對象,類似于C# 中的構(gòu)造函數(shù)。最后new返回這個對象。再看第二句:var obj2 = new myClass(); 執(zhí)行過程與上一句代碼相同,即創(chuàng)建一個空對象,然后執(zhí)行myClass這個函數(shù),定義兩個屬性和一個方法。
從上面的分析中可以看到,上面這種實現(xiàn)類的方式,即在函數(shù)的定義中定義類的屬性方法。存在著弊端。如果需要創(chuàng)建兩個或更多這個類的實例時,上文是兩個,這些屬性會被重復的創(chuàng)建多次。
那么如何避免這種情況呢?上一篇中也曾提到過用prototype。prototype和它的名字一樣是一個原型,每一個function都有一個子對象prototype,它其實表示這個function對象的成員的集合,由于這里我們使用function實現(xiàn)類的,所以可以說prototype其實就是便是類的成員的集合。prototype定義的屬性和方法執(zhí)行在函數(shù)的構(gòu)造體執(zhí)行之前,所以當new一個對象之前,其實prototype的成員已經(jīng)執(zhí)行過了。先看一個例子:
function myClass()
{
//構(gòu)造函數(shù)
}
myClass.prototype =
{
ID: 1,
Name: "johnson",
showMessage: function()
{
alert("ID: " + this.ID + ", Name: " + this.Name);
}
}
var obj1 = new myClass();
var obj2 = new myClass();
類的結(jié)構(gòu)還是和前面的例子相同,只不過這里是利用了prototype來實現(xiàn)。還是先看最后兩句,前面說過,prototype是執(zhí)行在函數(shù)構(gòu)造體之前,即執(zhí)行到var obj1 = new myClass();之前,這個類已經(jīng)有了ID,Name屬性和showMessage方法。執(zhí)行者一句時執(zhí)行過程如下,注意和前一個例子比較:首先還是創(chuàng)建一個空的對象,并把this指針指向這個對象。然后將函數(shù)的prototype對象的所有成員都賦給這個對象(注意沒有再創(chuàng)建這些成員)。然后執(zhí)行函數(shù)體。最后new返回這個對象。執(zhí)行下一句時:同樣執(zhí)行此過程,不會重復創(chuàng)建這些成員。
上面的代碼還只是一個例子,在實際的項目中,可能出現(xiàn)的是類中有大量的成員,同時可能需要創(chuàng)建大量的實例。這是prototype就會顯示其優(yōu)越性了。另外上面的代碼中使用了大括號語法定義了prototype的成員,這樣看起來代碼更清晰。這是一種比較推薦的類的設計模式。當然在眾多的項目中,可能還會發(fā)現(xiàn)更好的模式,我們也希望能有更優(yōu)化的JavaScript的編程模式不斷推陳出新,也希望隨著時間的推移,各主流瀏覽器也對JavaScript的解析都標準,統(tǒng)一。
上面說過prototype定義的成員是發(fā)生在構(gòu)造體之前,可以證明一下,在上面的例子中,構(gòu)造體是空的,在構(gòu)造函數(shù)中加入一句alert(this.Name);,當執(zhí)行到var obj1 = new myClass();時,會看到彈出對話框,顯示正確的屬性值。
寫了這段文字之后承蒙多為兄弟的點評,收獲匪淺。對上面的例子進一步討論,如下代碼:
function subClass(){ }
subClass.prototype =
{
Name: "sub"
}
function myClass()
{
//構(gòu)造函數(shù)
}
myClass.prototype =
{
ID: 1,
Name: "johnson",
SubObj: new subClass(),
showMessage: function()
{
alert("ID: " + this.ID + ", Name: " + this.Name + "SubObj.Name:" + this.SubObj.Name);
}
}
var obj1 = new myClass();
obj1.SubObj.Name = "XXX";
obj1.showMessage();
var obj2 = new myClass();
obj2.showMessage();
這里在myClass中定義了一個引用類型,其類型是我們自定義的一個subClass類,這個子類中有一個Name屬性。由于prototype對象是共享的,按照我們上面的分析:在執(zhí)行var obj1 = new myClass();時,會把myClass的prototype中的成員復制給這個obj1實例。但這里SubObj是一個引用類型,在執(zhí)行到var obj2 = new myClass();時,prototype中的ID,Name成員會復制到obj2中,但SubObj這個屬性不會復制過去,而是引用了prototype中的SubObj,所以因為上一句修改了obj1.Subobj.Name的值,所以在用new生成obj2實例時,引用到了修改后的值。
所以借用prototype定義類時,依然需要將屬性定義在構(gòu)造體中,而將方法定義在該構(gòu)造體的原型上。如下:
function myClass(id, name)
{
this.ID = id;
this.Name = name;
}
myClass.prototype =
{
showMessage: function()
{
alert("ID: " + this.ID + ", Name: " + this.Name);
},
showMessage2: function()
{
alert("Method2");
}
}
var obj1 = new myClass(1, "johnson");
obj1.showMessage();
obj1.Name="John";
obj1.showMessage();
var obj2 = new myClass(2, "Amanda");
obj2.showMessage();
關(guān)于私有成員,共有成員以及靜態(tài)成員,類的繼承,抽象類,虛方法,類的反射等實現(xiàn)方法,以后還會堅持寫下去。不過我覺得需要說一下的是,我打算寫的是JavaScript面向?qū)ο蟮幕A實現(xiàn),如果需要深入的學習建議參考李戰(zhàn)老哥的“甘露模型”。
上篇說過,JavaScript沒有類的概念,需要通過函數(shù)來實現(xiàn)類的定義。先通過一個例子說明:
復制代碼 代碼如下:
function myClass()
{
var id = 1;
var name = "johnson";
//properties
this.ID = id;
this.Name = name;
//method
this.showMessage = function()
{
alert("ID: " + this.ID + ", Name: " + this.Name);
}
}
var obj1 = new myClass();
var obj2 = new myClass();
function的定義實際上相當于類的構(gòu)造函數(shù),最后兩句是創(chuàng)建這個類的實例。先分析第一句:var obj1 = new myClass(); 當用new創(chuàng)建類的實例時,解釋器首先會創(chuàng)建一個空的對象。然后運行這個myClass函數(shù),并將this指針指向這個類的實例。當碰到this.ID = id;和this.Name = name;及this.showMessage = function(){...}時,便會創(chuàng)建這兩個屬性,和這個方法,并把變量id,name的值一級函數(shù)的定義賦給這兩個屬性及這個函數(shù)對象(shwoMessage)。這個過程相當于初始化這個對象,類似于C# 中的構(gòu)造函數(shù)。最后new返回這個對象。再看第二句:var obj2 = new myClass(); 執(zhí)行過程與上一句代碼相同,即創(chuàng)建一個空對象,然后執(zhí)行myClass這個函數(shù),定義兩個屬性和一個方法。
從上面的分析中可以看到,上面這種實現(xiàn)類的方式,即在函數(shù)的定義中定義類的屬性方法。存在著弊端。如果需要創(chuàng)建兩個或更多這個類的實例時,上文是兩個,這些屬性會被重復的創(chuàng)建多次。
那么如何避免這種情況呢?上一篇中也曾提到過用prototype。prototype和它的名字一樣是一個原型,每一個function都有一個子對象prototype,它其實表示這個function對象的成員的集合,由于這里我們使用function實現(xiàn)類的,所以可以說prototype其實就是便是類的成員的集合。prototype定義的屬性和方法執(zhí)行在函數(shù)的構(gòu)造體執(zhí)行之前,所以當new一個對象之前,其實prototype的成員已經(jīng)執(zhí)行過了。先看一個例子:
復制代碼 代碼如下:
function myClass()
{
//構(gòu)造函數(shù)
}
myClass.prototype =
{
ID: 1,
Name: "johnson",
showMessage: function()
{
alert("ID: " + this.ID + ", Name: " + this.Name);
}
}
var obj1 = new myClass();
var obj2 = new myClass();
類的結(jié)構(gòu)還是和前面的例子相同,只不過這里是利用了prototype來實現(xiàn)。還是先看最后兩句,前面說過,prototype是執(zhí)行在函數(shù)構(gòu)造體之前,即執(zhí)行到var obj1 = new myClass();之前,這個類已經(jīng)有了ID,Name屬性和showMessage方法。執(zhí)行者一句時執(zhí)行過程如下,注意和前一個例子比較:首先還是創(chuàng)建一個空的對象,并把this指針指向這個對象。然后將函數(shù)的prototype對象的所有成員都賦給這個對象(注意沒有再創(chuàng)建這些成員)。然后執(zhí)行函數(shù)體。最后new返回這個對象。執(zhí)行下一句時:同樣執(zhí)行此過程,不會重復創(chuàng)建這些成員。
上面的代碼還只是一個例子,在實際的項目中,可能出現(xiàn)的是類中有大量的成員,同時可能需要創(chuàng)建大量的實例。這是prototype就會顯示其優(yōu)越性了。另外上面的代碼中使用了大括號語法定義了prototype的成員,這樣看起來代碼更清晰。這是一種比較推薦的類的設計模式。當然在眾多的項目中,可能還會發(fā)現(xiàn)更好的模式,我們也希望能有更優(yōu)化的JavaScript的編程模式不斷推陳出新,也希望隨著時間的推移,各主流瀏覽器也對JavaScript的解析都標準,統(tǒng)一。
上面說過prototype定義的成員是發(fā)生在構(gòu)造體之前,可以證明一下,在上面的例子中,構(gòu)造體是空的,在構(gòu)造函數(shù)中加入一句alert(this.Name);,當執(zhí)行到var obj1 = new myClass();時,會看到彈出對話框,顯示正確的屬性值。
寫了這段文字之后承蒙多為兄弟的點評,收獲匪淺。對上面的例子進一步討論,如下代碼:
復制代碼 代碼如下:
function subClass(){ }
subClass.prototype =
{
Name: "sub"
}
function myClass()
{
//構(gòu)造函數(shù)
}
myClass.prototype =
{
ID: 1,
Name: "johnson",
SubObj: new subClass(),
showMessage: function()
{
alert("ID: " + this.ID + ", Name: " + this.Name + "SubObj.Name:" + this.SubObj.Name);
}
}
var obj1 = new myClass();
obj1.SubObj.Name = "XXX";
obj1.showMessage();
var obj2 = new myClass();
obj2.showMessage();
這里在myClass中定義了一個引用類型,其類型是我們自定義的一個subClass類,這個子類中有一個Name屬性。由于prototype對象是共享的,按照我們上面的分析:在執(zhí)行var obj1 = new myClass();時,會把myClass的prototype中的成員復制給這個obj1實例。但這里SubObj是一個引用類型,在執(zhí)行到var obj2 = new myClass();時,prototype中的ID,Name成員會復制到obj2中,但SubObj這個屬性不會復制過去,而是引用了prototype中的SubObj,所以因為上一句修改了obj1.Subobj.Name的值,所以在用new生成obj2實例時,引用到了修改后的值。
所以借用prototype定義類時,依然需要將屬性定義在構(gòu)造體中,而將方法定義在該構(gòu)造體的原型上。如下:
復制代碼 代碼如下:
function myClass(id, name)
{
this.ID = id;
this.Name = name;
}
myClass.prototype =
{
showMessage: function()
{
alert("ID: " + this.ID + ", Name: " + this.Name);
},
showMessage2: function()
{
alert("Method2");
}
}
var obj1 = new myClass(1, "johnson");
obj1.showMessage();
obj1.Name="John";
obj1.showMessage();
var obj2 = new myClass(2, "Amanda");
obj2.showMessage();
關(guān)于私有成員,共有成員以及靜態(tài)成員,類的繼承,抽象類,虛方法,類的反射等實現(xiàn)方法,以后還會堅持寫下去。不過我覺得需要說一下的是,我打算寫的是JavaScript面向?qū)ο蟮幕A實現(xiàn),如果需要深入的學習建議參考李戰(zhàn)老哥的“甘露模型”。
您可能感興趣的文章:
- 獲取JavaScript用戶自定義類的類名稱的代碼
- Javascript 自定義類型方法小結(jié)
- 關(guān)于JavaScript定義類和對象的幾種方式
- javascript來定義類的規(guī)范小結(jié)
- JavaScript定義類或函數(shù)的幾種方式小結(jié)
- javascript面向?qū)ο笾?定義類
- JavaScript之自定義類型
- JavaScript高級程序設計 閱讀筆記(十三) js定義類或?qū)ο?/a>
- JavaScript定義類的幾種方式總結(jié)
- JavaScript定義類和對象的方法
- javascript中定義類的方法匯總
- javascript中定義類的方法詳解
相關(guān)文章

Javascript面向?qū)ο缶幊蹋ǘ?構(gòu)造函數(shù)的繼承
這個系列的第一部分,主要介紹了如何"封裝"數(shù)據(jù)和方法,以及如何從原型對象生成實例。
2011-08-08 ![[推薦]javascript 面向?qū)ο蠹夹g(shù)基礎教程](http://img.jbzj.com/images/xgimg/bcimg4.png)
[推薦]javascript 面向?qū)ο蠹夹g(shù)基礎教程
看了很多介紹javascript面向?qū)ο蠹夹g(shù)的文章,很暈.為什么?不是因為寫得不好,而是因為太深奧.
javascript中的對象還沒解釋清楚怎么回事,一上來就直奔主題,類/繼承/原型/私有變量....
2009-03-03 
javascript 面向?qū)ο笕吕砭氈^承與多態(tài)
前面我們討論了如何在 JavaScript 語言中實現(xiàn)對私有實例成員、公有實例成員、私有靜態(tài)成員、公有靜態(tài)成員和靜態(tài)類的封裝。這次我們來討論一下面向?qū)ο蟪绦蛟O計中的另外兩個要素:繼承與多態(tài)。
2009-12-12 ![編寫可維護面向?qū)ο蟮腏avaScript代碼[翻譯]](http://img.jbzj.com/images/xgimg/bcimg6.png)
編寫可維護面向?qū)ο蟮腏avaScript代碼[翻譯],學習js面向?qū)ο缶帉懙呐笥芽梢詤⒖枷隆?/div> 2011-02-02

面向?qū)ο蟮腏avascript之一(初識Javascript)
Javascript是一門極富表現(xiàn)力的語言,在當今大行其道的Web浪潮中扮演著非常關(guān)鍵的作用。合理、高效地利用這門技術(shù),可以讓我們的Web世界多姿多彩。首先,我們認識一下這門技術(shù)的幾個獨特的特性
2012-01-01