上文一直在羅嗦GOF的原型模式,在本文中講開始正式討論Javascript的Prototype。對於Javascript的初學者來說,Prototype是個蠻高深的話題,其實並不盡然。
我說不盡然,意思是說理解Prototype的一般用法很簡單。但是真正能做到融會貫通理解Prototype確實是件很難的事情。
今天我就從Prototype的基本開始講。上文中我講了原型模式。其實在Javascript中原型也是這個意思。Javascript中對象的原型屬性的解釋是:返回物件類型原型的引用。這是一個暈人的解釋。其實就是指定了一個需要複製的對象。
文字再多也不如代碼,上代碼,說最簡單的,任何類都繼承自Object類:
function A()
{ }
A.prototype=new Object();
其實這樣就相當於Object對象是A的一個原型,這樣就相當於了把Object對象的屬性和方法複製到了A上,和原型模式的精髓一樣吧!
好,大概瞭解了prototype的基本用法,我們來看看原型究竟有什麼用處。
- 最簡單的用法,動態擴充類的方法和屬性。
function People()
{
this.Jump=function(){
alert("I can jump");
}
}
現在要擴充方法:
People.prototype.Run=function(){
alert("I can run,too");
}
好,測試下:
var p=new People();
p.Jump();
p.Run();
接下來,順帶講一下Javascript的方法種類。我個人將Javascript的方法分為三種:
<1>類方法
<2>對象方法
<3>原型方法
先看代碼,後講區別:
function People(name)
{
this.name=name;
//對象方法
this.Introduce=function(){
alert("My name is "+this.name);
}
}
//類方法
People.Run=function(){
alert("I can run");
}
//原型方法
People.prototype.IntroduceChinese=function(){
alert("我的名字是"+this.name);
}
測試下:
var p1=new People("Windking");
p1.Introduce();
People.Run();
p1.IntroduceChinese();
總結下:
名稱 |
位置 |
格式 |
類方法 |
類外 |
類名.方法名 |
對象方法 |
類內 |
this.方法名 |
原型方法 |
類外 |
類名.prototype.方法名 |
我們用C#來做類別來講解這三個方法:
類方法其實就是我們講的靜態方法:
如public static void Run(){}
而對象方法其實就是執行個體方法。
public void Introduce(){}
而原型方法有所不同,由於C#中不允許動態為對象增加方法,因此在C#中並不存在原型方法。原型方法處於C#的靜態方法與執行個體方法之間,通過對象調用,但是儲存的記憶體形式卻類似於靜態方法,也就是所有執行個體對象共用同一副本。
(ps:盡量將方法定義為原型方法,原型方法避免了每次調用建構函式時對屬性或方法的構造,因此比較節省空間的和時間)
- p1.IntroduceChinese();建立對象。
還記得我在上一篇文章裡講的淺複製嗎?為什麼大家都喜歡批量生產?效率是最主要因素。淺複製也一樣,我們為什麼要淺複製,因為效率高。作為原型模式的Javascript應用,prototype也承擔著這樣的重任。用prototype來建立對象,要比其他方式快得多。
看代碼例子:
function People(name,age)
{
this.name=name;
this.age=age;
}
var p1=new People("Xuan",22);
var girls=[ ];
var GirlPrototype=function(){};
GirlPrototype.prototype=p1;
for(var i=0;i<100000;i++)
{
girls[i]=new GirlPrototype();
}
- 玩轉繼承:
Prototype最大的應用其實還是在於玩轉繼承,這個在此不討論,請參加我的另一篇文章:《Javascript玩轉繼承(二)》。
好,基本的應用說完,下面我來說一下prototype的天使和魔鬼兩面。
說prototype是天使,是因為以上的幾點應用,讓Javascript增加了很大的靈活性,尤其原型繼承,更是Javascript最多的繼承方式。
說他是魔鬼,則是因為下面幾方面:
- 原型繼承的缺陷。請參見《Javascript玩轉繼承(二)》。
- 原型其實相當於原型模式中的淺複製,因此也會造成牽一髮而動全身的效果。
過於靈活。為什麼過於靈活呢?其實這點我是針對第一點來說的,能夠動態地添加屬性和方法固然是增加了靈活性。可是我們討論一種情況,100個人同時來開發一個Javascript的項目,很多沒經驗的人愛上了玩轉prototype,一個人往這個類裡加一個方法,還物件導向嗎?當然這隻是我的個人之見。如果有異議,歡迎和我討論。