在 C# 和 Java 語(yǔ)言中,面向?qū)ο笫且灶?lèi)的方式實(shí)現(xiàn)的,特別是繼承這個(gè)特性,類(lèi)的方式繼承表現(xiàn)出了強(qiáng)大的功能,而且也易于學(xué)習(xí)。JavaScript 不是純的面向?qū)ο蟮恼Z(yǔ)言,而是基于對(duì)象的語(yǔ)言,對(duì)象的繼承是以原型函數(shù)的形式繼承的,很多初學(xué)者剛開(kāi)始接觸的時(shí)候不太理解,但是 JavaScript 這種以原型函數(shù)的形式實(shí)現(xiàn)面向?qū)ο蠹夹g(shù),不僅是可行的,而且還為面向?qū)ο蠹夹g(shù)提供了動(dòng)態(tài)繼承的功能,本文主要討論了 JavaScript 的面向?qū)ο蠹夹g(shù)。
每個(gè) JavaScript 對(duì)象都有原型對(duì)象,對(duì)象都繼承原型對(duì)象的所有屬性。一個(gè)對(duì)象的原型是由創(chuàng)建該對(duì)象的構(gòu)造函數(shù)定義的。JavaScript 的所有函數(shù)都有一個(gè)名為 prototype 的屬性,該屬性引用了原型對(duì)象,該原型對(duì)象初始化的時(shí)候只有 constructor 屬性來(lái)引用創(chuàng)建該原型對(duì)象的對(duì)象。JavaScript 沒(méi)有 Class 定義類(lèi)的概念,構(gòu)造函數(shù)就定義了類(lèi),并初始化類(lèi)中的屬性,每個(gè)類(lèi)的成員都會(huì)從原型對(duì)象中繼承相同的屬性,也就是說(shuō),原型對(duì)象提供了類(lèi)的實(shí)例共享的屬性和方法,這就節(jié)約了內(nèi)存。
當(dāng)讀取一個(gè)對(duì)象的屬性的時(shí)候,JavaScript 會(huì)先從對(duì)象中查找,如果沒(méi)有查找到,才會(huì)到原型對(duì)象中查找該屬性(或方法),所以,尤其是對(duì)于方法,最好保存到原型對(duì)象中以便于共享,并且達(dá)到節(jié)省內(nèi)存的目的,而且原型對(duì)象還有一個(gè)強(qiáng)大的功能,那就是如果通過(guò)構(gòu)造函數(shù)實(shí)例化一些對(duì)象后,再給構(gòu)造函數(shù)的原型對(duì)象增加屬性和方法,那么它原來(lái)實(shí)例化的對(duì)象實(shí)例將會(huì)繼承這些增加的屬性和方法。
每個(gè)對(duì)象都會(huì)有自己?jiǎn)为?dú)的實(shí)例屬性和實(shí)例方法的副本,如果實(shí)例化 5 個(gè)對(duì)象,那么就會(huì)有 5 個(gè)對(duì)象的實(shí)例屬性和實(shí)例方法副本。this 關(guān)鍵字引用它們的實(shí)例對(duì)象,也就是說(shuō),誰(shuí)操作了實(shí)例方法,this 就引用誰(shuí);訪問(wèn)了哪個(gè)實(shí)例對(duì)象的屬性,this 就引用這個(gè)實(shí)例對(duì)象。
類(lèi)方法和類(lèi)屬性只有一個(gè)副本,類(lèi)方法調(diào)用的時(shí)候必須引用類(lèi)的名字,例如:Date.setHours();
下面用一個(gè)程序來(lái)表現(xiàn)實(shí)例屬性、實(shí)例方法、類(lèi)屬性、類(lèi)方法
function Mobile(kind,brand) {
this.kind=kind;// 定義手機(jī)的種類(lèi),例如 GSM/CDMA
this.brand=brand;// 定義手機(jī)的品牌,this 關(guān)鍵字表示用該構(gòu)造函數(shù)實(shí)例化之后的對(duì)象
}
/**//*
定義類(lèi)的第二步是在構(gòu)造函數(shù)的原型對(duì)象中定義它的實(shí)例方法或其他屬性
該對(duì)象定義的任何屬性都將這個(gè)類(lèi)的所有實(shí)例繼承。
*/
// 撥號(hào),這里只是返回電話號(hào)碼
Mobile.prototype.dial = function(phoneNo) {
return phoneNo;
};
/**//*
定義類(lèi)的第三步是定義類(lèi)方法,常量和其他必要的類(lèi)屬性,作為構(gòu)造函數(shù)自身的屬性,而不是構(gòu)造函數(shù)
原型對(duì)象的屬性,注意,類(lèi)方法沒(méi)有使用關(guān)鍵字 this,因?yàn)樗麄冎粚?duì)他們的實(shí)際參數(shù)進(jìn)行操作。
*/
// 開(kāi)機(jī)關(guān)機(jī)方法
Mobile.turnOn=function() {
return "The power of mobile is on";
}
Mobile.turnOff=function() {
return "The power of mobile is off";
}
```
// 類(lèi)屬性,這樣他們就可以被用作常量,注意實(shí)際上他們并不是只讀的
`Mobile.screenColor=64K;//` 假設(shè)該類(lèi)手機(jī)的屏幕顏色都是 64K 彩屏的
## 子類(lèi)化
JavaScript 支持子類(lèi)化,只需把子類(lèi)的原型對(duì)象用超類(lèi)實(shí)例化即可,但是應(yīng)該注意,這樣子類(lèi)化之后就會(huì)存在一個(gè)問(wèn)題,由于是用超類(lèi)實(shí)例化子類(lèi)的原型對(duì)象取得的,所以就沖掉了自己本身的由 JavaScript 提供的 constructor 屬性,為了確保 constructor 的正確性,需要重新指定一下,子類(lèi)化的程序例子如下:
<pre><code>
/***** 子類(lèi)化 *****/
// 下面是子類(lèi)構(gòu)造函數(shù)智能型手機(jī)
function SmartPhone(os)
{
this.os=os;
}
// 我們將 Mobile 對(duì)象作為它的原型
// 這意味著新類(lèi)的實(shí)例將繼承 SmartPhone.prototype,
// 后者由 Mobile.prototype 繼承而來(lái)
//Mobile.prototype 又由 Object.prototype 繼承而來(lái)
SmartPhone.prototype=new Mobile(GSM,Nokia);
// 下面給子類(lèi)添加一個(gè)新方法,發(fā)送電子郵件,這里只是返回 Email 地址
SmartPhone.prototype.sendEmail=function(emailAddress) {
return this.emailAddress
}
// 上面的子類(lèi)化方法有一點(diǎn)缺陷,由于我們明確把 SmartPhone.prototype 設(shè)成了我們所創(chuàng)建的一個(gè)對(duì)象,所以就覆蓋了 JS 提供
// 的原型對(duì)象,而且丟棄了給定的 Constructor 屬性。該屬性引用的是創(chuàng)建這個(gè)對(duì)象的構(gòu)造函數(shù)。但是 SmartPhone 對(duì)象集成了它的
// 父類(lèi)的 constructor,它自己沒(méi)有這個(gè)屬性,明確設(shè)置著一個(gè)屬性可以解決這個(gè)問(wèn)題:
SmartPhone.prototype.constructor=SmartPhone;
var objSmartPhone=new SmartPhone();// 實(shí)例化子類(lèi)
</code></pre>