JavaScript面向对象编程
生活随笔
收集整理的這篇文章主要介紹了
JavaScript面向对象编程
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
自從有了Ajax這個(gè)概念,JavaScript作為Ajax的利器,其作用一路飆升。JavaScript最基本的使用,以及語法、瀏覽器對象等等東東在這里就不累贅了。把主要篇幅放在如何實(shí)現(xiàn)JavaScript的面向?qū)ο缶幊谭矫妗?
??? 1. 用JavaScript實(shí)現(xiàn)類
??? ?? JavaScritpt沒有專門的機(jī)制實(shí)現(xiàn)類,這里是借助它的函數(shù)允許嵌套的機(jī)制來實(shí)現(xiàn)類的。一個(gè)函數(shù)可以包含變量,又可以包含其它函數(shù),這樣,變量可以作為屬性,內(nèi)部的函數(shù)就可以作為成員方法了。因此外層函數(shù)本身就可以作為一個(gè)類了。如下:
function?myClass()
{
???//此處相當(dāng)于構(gòu)造函數(shù)
} 這里 myClass就是一個(gè)類。其實(shí)可以把它看成類的構(gòu)造函數(shù)。至于非構(gòu)造函數(shù)的部分,以后會詳細(xì)描述。
??? 2. 如何獲得一個(gè)類的實(shí)例
????? 實(shí)現(xiàn)了類就應(yīng)該可以獲得類的實(shí)例,JavaScript提供了一個(gè)方法可以獲得對象實(shí)例。即 new操作符。其實(shí)JavaScript中,類和函數(shù)是同一個(gè)概念,當(dāng)用new操作一個(gè)函數(shù)時(shí)就返回一個(gè)對象。如下:
var obj1?=?new?myClass();
??? 3. 對象的成員的引用
?????? 在JavaScript中引用一個(gè)類的屬性或方法的方法有以下三種。
?????? 1>? 點(diǎn)號操作符
??????????? 這是一種最普遍的引用方式,就不累贅。即如下形式:
對象名.屬性名;
對象名.方法名;
????? 2>? 方括號引用
?????????? JavaScript中允許用方括號引用對象的成員。如下:
對象名["屬性名"];
對象名["方法名"]; ??????????? 這里方括號內(nèi)是代表屬性或方法名的字符串,不一定是字符串常量。也可以使用變量。這樣就可以使用變量傳遞屬性或方法名。為編程帶來了方便。在某些情況下,代碼中不能確定要調(diào)用那個(gè)屬性或方法時(shí),就可以采用這種方式。否則,如果使用點(diǎn)號操作符,還需要使用條件判斷來調(diào)用屬性或方法。
?????? 另外,使用方括號引用的屬性和方法名還可以以數(shù)字開頭,或者出現(xiàn)空格,而使用點(diǎn)號引用的屬性和方法名則遵循標(biāo)示符的規(guī)則。但一般不提倡使用非標(biāo)示符的命名方法。
?
????? 3>? 使用eval函數(shù)
?????????? 如果不希望使用變量傳遞變量或方法名,又不想使用條件判斷,那么eval函數(shù)是一個(gè)好的選擇。eval接收一個(gè)字符串類型的參數(shù),然后將這個(gè)字符串作為代碼在上下文中執(zhí)行,返回執(zhí)行的結(jié)果。這里正是利用了eval的這一功能。如下:
alert(eval("對象名."?+?element.value)); ????????
???? 4. 對對象屬性,方法的添加、修改和刪除操作
???????? JavaScript中,在生成對象之后還可以為對象動態(tài)添加、修改和刪除屬性和方法,這與其它面向?qū)ο蟮恼Z言是不同的。
??????? 1>? 添加屬性和方法
????????????? 先創(chuàng)建一個(gè)對象,空對象創(chuàng)建后沒有任何屬性和方法,然而我們可以在代碼中創(chuàng)建。
var?obj1?=?new?Object();
//添加屬性
obj1.ID?=?1;
obj1.Name?=?"johnson";
//添加方法
obj1.showMessage?=?function()
{
????alert("ID:?"?+?this.ID?+?",?Name:?"?+?this.Name);
}
????? 2>? 修改屬性與方法
??????????? 與添加屬性和方法類似,例如接著上面的例子:
//?修改屬性
obj1.ID?=?2;
obj1.Name?=?"Amanda";
//?修改方法
obj1.showMessage?=?function()
{
????alert("ID:?"?+?this.ID");
} ????
????? 3>? 刪除屬性與方法
??????????? 直接將要刪除的屬性或方法賦值為undefined即可:
?? obj1.ID?= 1;
obj1.Name?=?undefined;
obj1.showMessage?=?undefined;
var?obj2?=?
{
????ID:?1,
????Name:?"Johnson",
????showMessage:?function()
????{
????????alert("ID:?"?+?this.ID?+?"Name:?"?+?this.Name);
????}
}
?????? 這里定義了兩個(gè)無類型的對象,obj1和obj2。其中obj1是一個(gè)空對象。obj2包括兩個(gè)屬性ID, Name和一個(gè)方法showMessage。每個(gè)屬性和方法用逗號分割。屬性(方法)名和其值之間用分號分割。
?????? 用這種方式創(chuàng)建屬性方法時(shí),也可以用字符串定義屬性方法的名字。如:
var?obj2?=?
{
????"ID"?:?1,
????"Name":?"Johnson"
} ?
????? 6. prototype
????????? 每個(gè)函數(shù)對象都具有一個(gè)子對象prototype,因?yàn)楹瘮?shù)也可以表示類,所以prototype表示一個(gè)類的成員的集合。當(dāng)new 一個(gè)對象時(shí),prototype對象的成員都會被實(shí)例化成對象的成員。先看一個(gè)例子:
function?myClass()
{?}
myClass.prototype.ID?=?1;
myClass.prototype.Name?=?"johnson";
myClass.prototype.showMessage?=?function()
{
????alert("ID:?"?+?this.ID?+?"Name:?"?+?this.Name);
}
var?obj1?=?new?myClass();
obj1.showMessage(); ????? 使用prototype對象創(chuàng)建類有一個(gè)好處。如果將所有的成員直接寫在類的聲明中,如下:
function?myClass()
{
????//添加屬性
????this.ID?=?1;
????this.Name?=?"johnson";
????//添加方法
????this.showMessage?=?function()
????{
????????alert("ID:?"?+?this.ID?+?",?Name:?"?+?this.Name);
????}
}
var?obj1?=?new?myClass();
var?obj2?=?new?myClass(); ??????? 在上面的代碼中,定義了一個(gè)類myClass,在類中直接定義了兩個(gè)屬性和一個(gè)方法。然后實(shí)例化了兩個(gè)對象,這里的兩個(gè)屬性和一個(gè)方法,每創(chuàng)建一次myClass對象都會被創(chuàng)建一次,浪費(fèi)了內(nèi)存空間。而用prototype以后就可以解決這個(gè)問題,每new一個(gè)函數(shù)時(shí),其prototype對象的成員都會自動賦給這個(gè)對象,當(dāng)new多個(gè)對象時(shí)不會重復(fù)創(chuàng)建。
??????? 由于prototype的初始化發(fā)生在函數(shù)體執(zhí)行之前,用以下代碼可以證明:
function?myClass()
{
????//此處相當(dāng)于構(gòu)造函數(shù)
????this.ID?=?1;
????this.Name1 =?this.Name;
????this.showMessage();
}
myClass.prototype.Name?=?"johnson";
myClass.prototype.showMessage?=?function()
{
????alert("ID:?"?+?this.ID?+?",?Name:?"?+?this.Name);
}
var?obj1?=?new?myClass();
??????? 執(zhí)行以上代碼可以發(fā)現(xiàn)當(dāng)new這個(gè)類型的對象時(shí),即彈出了對話框。
??????? 最后只得一提的是,prototype有一個(gè)方法,在面向?qū)ο蟮脑O(shè)計(jì)中用得到。即:constructor屬性,是對構(gòu)造函數(shù)的調(diào)用,這里的構(gòu)造函數(shù)即上文提到的類的聲明里的代碼。如:
function?myClass()
{
????//此處相當(dāng)于構(gòu)造函數(shù)
????alert("this?is?in?constructor");
}
myClass.prototype.constructor();
var?obj1?=?new?myClass(); ?? 執(zhí)行以上代碼你會發(fā)現(xiàn)對話框彈出了兩次。由此可見,prototype可專門用于設(shè)計(jì)類的成員,實(shí)際上在JavaScript面向?qū)ο蟮脑O(shè)計(jì)中,很多時(shí)候都會用到prototype。
JavaScript沒有類的概念,需要通過函數(shù)來實(shí)現(xiàn)類的定義。先通過一個(gè)例子說明:
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的定義實(shí)際上相當(dāng)于類的構(gòu)造函數(shù),最后兩句是創(chuàng)建這個(gè)類的實(shí)例。先分析第一句: var ?obj1? =? new ?myClass(); 當(dāng)用new創(chuàng)建類的實(shí)例時(shí),解釋器首先會創(chuàng)建一個(gè)空的對象。然后運(yùn)行這個(gè)myClass函數(shù),并將this指針指向這個(gè)類的實(shí)例。當(dāng)碰到 this.ID?=?id;和 this.Name?=?name;及 this.showMessage?=?function(){...}時(shí),便會創(chuàng)建這兩個(gè)屬性,和這個(gè)方法,并把變量id,name的值一級函數(shù)的定義賦給這兩個(gè)屬性及這個(gè)函數(shù)對象(shwoMessage)。這個(gè)過程相當(dāng)于初始化這個(gè)對象,類似于C# 中的構(gòu)造函數(shù)。最后new返回這個(gè)對象。再看第二句: var ?obj2 =? new ?myClass(); 執(zhí)行過程與上一句代碼相同,即創(chuàng)建一個(gè)空對象,然后執(zhí)行myClass這個(gè)函數(shù),定義兩個(gè)屬性和一個(gè)方法。
???
??? 從上面的分析中可以看到,上面這種實(shí)現(xiàn)類的方式,即在函數(shù)的定義中定義類的屬性方法。存在著弊端。如果需要創(chuàng)建兩個(gè)或更多這個(gè)類的實(shí)例時(shí),上文是兩個(gè),這些屬性會被重復(fù)的創(chuàng)建多次。
???
??? 那么如何避免這種情況呢?上一篇中也曾提到過用prototype。prototype和它的名字一樣是一個(gè)原型,每一個(gè)function都有一個(gè)子對象prototype,它其實(shí)表示這個(gè)function對象的成員的集合,由于這里我們使用function實(shí)現(xiàn)類的,所以可以說prototype其實(shí)就是便是類的成員的集合。prototype定義的屬性和方法執(zhí)行在函數(shù)的構(gòu)造體執(zhí)行之前,所以當(dāng)new一個(gè)對象之前,其實(shí)prototype的成員已經(jīng)執(zhí)行過了。先看一個(gè)例子:
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來實(shí)現(xiàn)。還是先看最后兩句,前面說過,prototype是執(zhí)行在函數(shù)構(gòu)造體之前,即執(zhí)行到 var ?obj1? =? new ?myClass();之前,這個(gè)類已經(jīng)有了ID,Name屬性和showMessage方法。執(zhí)行者一句時(shí)執(zhí)行過程如下,注意和前一個(gè)例子比較:首先還是創(chuàng)建一個(gè)空的對象,并把this指針指向這個(gè)對象。然后將函數(shù)的prototype對象的所有成員都賦給這個(gè)對象(注意沒有再創(chuàng)建這些成員)。然后執(zhí)行函數(shù)體。最后new返回這個(gè)對象。執(zhí)行下一句時(shí):同樣執(zhí)行此過程,不會重復(fù)創(chuàng)建這些成員。
???
??? 上面的代碼還只是一個(gè)例子,在實(shí)際的項(xiàng)目中,可能出現(xiàn)的是類中有大量的成員,同時(shí)可能需要創(chuàng)建大量的實(shí)例。這是prototype就會顯示其優(yōu)越性了。另外上面的代碼中使用了大括號語法定義了prototype的成員,這樣看起來代碼更清晰。這是一種比較推薦的類的設(shè)計(jì)模式。當(dāng)然在眾多的項(xiàng)目中,可能還會發(fā)現(xiàn)更好的模式,我們也希望能有更優(yōu)化的JavaScript的編程模式不斷推陳出新,也希望隨著時(shí)間的推移,各主流瀏覽器也對JavaScript的解析都標(biāo)準(zhǔn),統(tǒng)一。
??? 上面說過prototype定義的成員是發(fā)生在構(gòu)造體之前,可以證明一下,在上面的例子中,構(gòu)造體是空的,在構(gòu)造函數(shù)中加入一句 alert( this .Name);,當(dāng)執(zhí)行到 var ?obj1?=? new ?myClass();時(shí),會看到彈出對話框,顯示正確的屬性值。
????? 寫了這段文字之后承蒙多為兄弟的點(diǎn)評,收獲匪淺。對上面的例子進(jìn)一步討論,如下代碼:
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中定義了一個(gè)引用類型,其類型是我們自定義的一個(gè)subClass類,這個(gè)子類中有一個(gè)Name屬性。由于prototype對象是共享的,按照我們上面的分析:在執(zhí)行 var ?obj1? =? new ?myClass();時(shí),會把myClass的prototype中的成員復(fù)制給這個(gè)obj1實(shí)例。但這里SubObj是一個(gè)引用類型,在執(zhí)行到 var ?obj2? =? new ?myClass();時(shí),prototype中的ID,Name成員會復(fù)制到obj2中,但SubObj這個(gè)屬性不會復(fù)制過去,而是引用了prototype中的SubObj,所以因?yàn)樯弦痪湫薷牧薿bj1.Subobj.Name的值,所以在用new生成obj2實(shí)例時(shí),引用到了修改后的值。
??? 所以借用prototype定義類時(shí),依然需要將屬性定義在構(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();
??? 1. 用JavaScript實(shí)現(xiàn)類
??? ?? JavaScritpt沒有專門的機(jī)制實(shí)現(xiàn)類,這里是借助它的函數(shù)允許嵌套的機(jī)制來實(shí)現(xiàn)類的。一個(gè)函數(shù)可以包含變量,又可以包含其它函數(shù),這樣,變量可以作為屬性,內(nèi)部的函數(shù)就可以作為成員方法了。因此外層函數(shù)本身就可以作為一個(gè)類了。如下:
function?myClass()
{
???//此處相當(dāng)于構(gòu)造函數(shù)
} 這里 myClass就是一個(gè)類。其實(shí)可以把它看成類的構(gòu)造函數(shù)。至于非構(gòu)造函數(shù)的部分,以后會詳細(xì)描述。
??? 2. 如何獲得一個(gè)類的實(shí)例
????? 實(shí)現(xiàn)了類就應(yīng)該可以獲得類的實(shí)例,JavaScript提供了一個(gè)方法可以獲得對象實(shí)例。即 new操作符。其實(shí)JavaScript中,類和函數(shù)是同一個(gè)概念,當(dāng)用new操作一個(gè)函數(shù)時(shí)就返回一個(gè)對象。如下:
var obj1?=?new?myClass();
??? 3. 對象的成員的引用
?????? 在JavaScript中引用一個(gè)類的屬性或方法的方法有以下三種。
?????? 1>? 點(diǎn)號操作符
??????????? 這是一種最普遍的引用方式,就不累贅。即如下形式:
對象名.屬性名;
對象名.方法名;
????? 2>? 方括號引用
?????????? JavaScript中允許用方括號引用對象的成員。如下:
對象名["屬性名"];
對象名["方法名"]; ??????????? 這里方括號內(nèi)是代表屬性或方法名的字符串,不一定是字符串常量。也可以使用變量。這樣就可以使用變量傳遞屬性或方法名。為編程帶來了方便。在某些情況下,代碼中不能確定要調(diào)用那個(gè)屬性或方法時(shí),就可以采用這種方式。否則,如果使用點(diǎn)號操作符,還需要使用條件判斷來調(diào)用屬性或方法。
?????? 另外,使用方括號引用的屬性和方法名還可以以數(shù)字開頭,或者出現(xiàn)空格,而使用點(diǎn)號引用的屬性和方法名則遵循標(biāo)示符的規(guī)則。但一般不提倡使用非標(biāo)示符的命名方法。
?
????? 3>? 使用eval函數(shù)
?????????? 如果不希望使用變量傳遞變量或方法名,又不想使用條件判斷,那么eval函數(shù)是一個(gè)好的選擇。eval接收一個(gè)字符串類型的參數(shù),然后將這個(gè)字符串作為代碼在上下文中執(zhí)行,返回執(zhí)行的結(jié)果。這里正是利用了eval的這一功能。如下:
alert(eval("對象名."?+?element.value)); ????????
???? 4. 對對象屬性,方法的添加、修改和刪除操作
???????? JavaScript中,在生成對象之后還可以為對象動態(tài)添加、修改和刪除屬性和方法,這與其它面向?qū)ο蟮恼Z言是不同的。
??????? 1>? 添加屬性和方法
????????????? 先創(chuàng)建一個(gè)對象,空對象創(chuàng)建后沒有任何屬性和方法,然而我們可以在代碼中創(chuàng)建。
var?obj1?=?new?Object();
//添加屬性
obj1.ID?=?1;
obj1.Name?=?"johnson";
//添加方法
obj1.showMessage?=?function()
{
????alert("ID:?"?+?this.ID?+?",?Name:?"?+?this.Name);
}
????? 2>? 修改屬性與方法
??????????? 與添加屬性和方法類似,例如接著上面的例子:
//?修改屬性
obj1.ID?=?2;
obj1.Name?=?"Amanda";
//?修改方法
obj1.showMessage?=?function()
{
????alert("ID:?"?+?this.ID");
} ????
????? 3>? 刪除屬性與方法
??????????? 直接將要刪除的屬性或方法賦值為undefined即可:
?? obj1.ID?= 1;
obj1.Name?=?undefined;
obj1.showMessage?=?undefined;
???? 5. 創(chuàng)建無類型對象。
??????? 注意屬性用“,”間隔而不是“;”間隔!
var?obj2?=?
{
????ID:?1,
????Name:?"Johnson",
????showMessage:?function()
????{
????????alert("ID:?"?+?this.ID?+?"Name:?"?+?this.Name);
????}
}
?????? 這里定義了兩個(gè)無類型的對象,obj1和obj2。其中obj1是一個(gè)空對象。obj2包括兩個(gè)屬性ID, Name和一個(gè)方法showMessage。每個(gè)屬性和方法用逗號分割。屬性(方法)名和其值之間用分號分割。
?????? 用這種方式創(chuàng)建屬性方法時(shí),也可以用字符串定義屬性方法的名字。如:
var?obj2?=?
{
????"ID"?:?1,
????"Name":?"Johnson"
} ?
????? 6. prototype
????????? 每個(gè)函數(shù)對象都具有一個(gè)子對象prototype,因?yàn)楹瘮?shù)也可以表示類,所以prototype表示一個(gè)類的成員的集合。當(dāng)new 一個(gè)對象時(shí),prototype對象的成員都會被實(shí)例化成對象的成員。先看一個(gè)例子:
function?myClass()
{?}
myClass.prototype.ID?=?1;
myClass.prototype.Name?=?"johnson";
myClass.prototype.showMessage?=?function()
{
????alert("ID:?"?+?this.ID?+?"Name:?"?+?this.Name);
}
var?obj1?=?new?myClass();
obj1.showMessage(); ????? 使用prototype對象創(chuàng)建類有一個(gè)好處。如果將所有的成員直接寫在類的聲明中,如下:
function?myClass()
{
????//添加屬性
????this.ID?=?1;
????this.Name?=?"johnson";
????//添加方法
????this.showMessage?=?function()
????{
????????alert("ID:?"?+?this.ID?+?",?Name:?"?+?this.Name);
????}
}
var?obj1?=?new?myClass();
var?obj2?=?new?myClass(); ??????? 在上面的代碼中,定義了一個(gè)類myClass,在類中直接定義了兩個(gè)屬性和一個(gè)方法。然后實(shí)例化了兩個(gè)對象,這里的兩個(gè)屬性和一個(gè)方法,每創(chuàng)建一次myClass對象都會被創(chuàng)建一次,浪費(fèi)了內(nèi)存空間。而用prototype以后就可以解決這個(gè)問題,每new一個(gè)函數(shù)時(shí),其prototype對象的成員都會自動賦給這個(gè)對象,當(dāng)new多個(gè)對象時(shí)不會重復(fù)創(chuàng)建。
??????? 由于prototype的初始化發(fā)生在函數(shù)體執(zhí)行之前,用以下代碼可以證明:
function?myClass()
{
????//此處相當(dāng)于構(gòu)造函數(shù)
????this.ID?=?1;
????this.Name1 =?this.Name;
????this.showMessage();
}
myClass.prototype.Name?=?"johnson";
myClass.prototype.showMessage?=?function()
{
????alert("ID:?"?+?this.ID?+?",?Name:?"?+?this.Name);
}
var?obj1?=?new?myClass();
??????? 執(zhí)行以上代碼可以發(fā)現(xiàn)當(dāng)new這個(gè)類型的對象時(shí),即彈出了對話框。
??????? 最后只得一提的是,prototype有一個(gè)方法,在面向?qū)ο蟮脑O(shè)計(jì)中用得到。即:constructor屬性,是對構(gòu)造函數(shù)的調(diào)用,這里的構(gòu)造函數(shù)即上文提到的類的聲明里的代碼。如:
function?myClass()
{
????//此處相當(dāng)于構(gòu)造函數(shù)
????alert("this?is?in?constructor");
}
myClass.prototype.constructor();
var?obj1?=?new?myClass(); ?? 執(zhí)行以上代碼你會發(fā)現(xiàn)對話框彈出了兩次。由此可見,prototype可專門用于設(shè)計(jì)類的成員,實(shí)際上在JavaScript面向?qū)ο蟮脑O(shè)計(jì)中,很多時(shí)候都會用到prototype。
JavaScript沒有類的概念,需要通過函數(shù)來實(shí)現(xiàn)類的定義。先通過一個(gè)例子說明:
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的定義實(shí)際上相當(dāng)于類的構(gòu)造函數(shù),最后兩句是創(chuàng)建這個(gè)類的實(shí)例。先分析第一句: var ?obj1? =? new ?myClass(); 當(dāng)用new創(chuàng)建類的實(shí)例時(shí),解釋器首先會創(chuàng)建一個(gè)空的對象。然后運(yùn)行這個(gè)myClass函數(shù),并將this指針指向這個(gè)類的實(shí)例。當(dāng)碰到 this.ID?=?id;和 this.Name?=?name;及 this.showMessage?=?function(){...}時(shí),便會創(chuàng)建這兩個(gè)屬性,和這個(gè)方法,并把變量id,name的值一級函數(shù)的定義賦給這兩個(gè)屬性及這個(gè)函數(shù)對象(shwoMessage)。這個(gè)過程相當(dāng)于初始化這個(gè)對象,類似于C# 中的構(gòu)造函數(shù)。最后new返回這個(gè)對象。再看第二句: var ?obj2 =? new ?myClass(); 執(zhí)行過程與上一句代碼相同,即創(chuàng)建一個(gè)空對象,然后執(zhí)行myClass這個(gè)函數(shù),定義兩個(gè)屬性和一個(gè)方法。
???
??? 從上面的分析中可以看到,上面這種實(shí)現(xiàn)類的方式,即在函數(shù)的定義中定義類的屬性方法。存在著弊端。如果需要創(chuàng)建兩個(gè)或更多這個(gè)類的實(shí)例時(shí),上文是兩個(gè),這些屬性會被重復(fù)的創(chuàng)建多次。
???
??? 那么如何避免這種情況呢?上一篇中也曾提到過用prototype。prototype和它的名字一樣是一個(gè)原型,每一個(gè)function都有一個(gè)子對象prototype,它其實(shí)表示這個(gè)function對象的成員的集合,由于這里我們使用function實(shí)現(xiàn)類的,所以可以說prototype其實(shí)就是便是類的成員的集合。prototype定義的屬性和方法執(zhí)行在函數(shù)的構(gòu)造體執(zhí)行之前,所以當(dāng)new一個(gè)對象之前,其實(shí)prototype的成員已經(jīng)執(zhí)行過了。先看一個(gè)例子:
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來實(shí)現(xiàn)。還是先看最后兩句,前面說過,prototype是執(zhí)行在函數(shù)構(gòu)造體之前,即執(zhí)行到 var ?obj1? =? new ?myClass();之前,這個(gè)類已經(jīng)有了ID,Name屬性和showMessage方法。執(zhí)行者一句時(shí)執(zhí)行過程如下,注意和前一個(gè)例子比較:首先還是創(chuàng)建一個(gè)空的對象,并把this指針指向這個(gè)對象。然后將函數(shù)的prototype對象的所有成員都賦給這個(gè)對象(注意沒有再創(chuàng)建這些成員)。然后執(zhí)行函數(shù)體。最后new返回這個(gè)對象。執(zhí)行下一句時(shí):同樣執(zhí)行此過程,不會重復(fù)創(chuàng)建這些成員。
???
??? 上面的代碼還只是一個(gè)例子,在實(shí)際的項(xiàng)目中,可能出現(xiàn)的是類中有大量的成員,同時(shí)可能需要創(chuàng)建大量的實(shí)例。這是prototype就會顯示其優(yōu)越性了。另外上面的代碼中使用了大括號語法定義了prototype的成員,這樣看起來代碼更清晰。這是一種比較推薦的類的設(shè)計(jì)模式。當(dāng)然在眾多的項(xiàng)目中,可能還會發(fā)現(xiàn)更好的模式,我們也希望能有更優(yōu)化的JavaScript的編程模式不斷推陳出新,也希望隨著時(shí)間的推移,各主流瀏覽器也對JavaScript的解析都標(biāo)準(zhǔn),統(tǒng)一。
??? 上面說過prototype定義的成員是發(fā)生在構(gòu)造體之前,可以證明一下,在上面的例子中,構(gòu)造體是空的,在構(gòu)造函數(shù)中加入一句 alert( this .Name);,當(dāng)執(zhí)行到 var ?obj1?=? new ?myClass();時(shí),會看到彈出對話框,顯示正確的屬性值。
????? 寫了這段文字之后承蒙多為兄弟的點(diǎn)評,收獲匪淺。對上面的例子進(jìn)一步討論,如下代碼:
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中定義了一個(gè)引用類型,其類型是我們自定義的一個(gè)subClass類,這個(gè)子類中有一個(gè)Name屬性。由于prototype對象是共享的,按照我們上面的分析:在執(zhí)行 var ?obj1? =? new ?myClass();時(shí),會把myClass的prototype中的成員復(fù)制給這個(gè)obj1實(shí)例。但這里SubObj是一個(gè)引用類型,在執(zhí)行到 var ?obj2? =? new ?myClass();時(shí),prototype中的ID,Name成員會復(fù)制到obj2中,但SubObj這個(gè)屬性不會復(fù)制過去,而是引用了prototype中的SubObj,所以因?yàn)樯弦痪湫薷牧薿bj1.Subobj.Name的值,所以在用new生成obj2實(shí)例時(shí),引用到了修改后的值。
??? 所以借用prototype定義類時(shí),依然需要將屬性定義在構(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();
總結(jié)
以上是生活随笔為你收集整理的JavaScript面向对象编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 黄山风景区最近的高铁站
- 下一篇: 求一个qq网名个性网女生精选!