面向?qū)ο蟮木幊趟枷朐趈avascript中的運(yùn)用上部
更新時(shí)間:2009年11月20日 22:00:38 作者:
對(duì)于正在從事或者打算從事編程的人來(lái)說(shuō),面向?qū)ο笫且粋€(gè)耳熟能詳?shù)脑~,幾乎每一個(gè)人都能列舉出一些面向?qū)ο蟮木幊陶Z(yǔ)言,例如C++,JAVA,C#等等。
其實(shí),面向?qū)ο蟮乃枷胧仟?dú)立于編程語(yǔ)言的,例如在C#中,在一個(gè)靜態(tài)類的靜態(tài)方法中,按照過(guò)程式開(kāi)發(fā)調(diào)用一系列靜態(tài)函數(shù),我們很難說(shuō)這是面向?qū)ο蟮木幊?,相反,象jquery和extjs這樣優(yōu)秀的javascript庫(kù),卻處處體現(xiàn)著面向?qū)ο蟮脑O(shè)計(jì)思想。本文不打算探討javascript是否能夠算做面向?qū)ο蟮木幊陶Z(yǔ)言,這個(gè)問(wèn)題是重視中國(guó)式考試的人應(yīng)該關(guān)注的,我這里只是簡(jiǎn)單的說(shuō)明如何在javascript中使用面向?qū)ο蟮木幊趟枷搿?
面向?qū)ο笫紫纫袑?duì)象。在javascript中創(chuàng)建一個(gè)對(duì)象非常簡(jiǎn)單:
var o={};
這樣就產(chǎn)生了一個(gè)對(duì)象,我們可以很方便的給這個(gè)對(duì)象添加屬性和方法:
o.name="object name";
o.showName=function(){
alert(o.name);
}
不過(guò)大多數(shù)人還是習(xí)慣把對(duì)象的屬性和方法放在定義對(duì)象的一對(duì){}里邊:
var o = {
name: "object name",
showName: function() {
alert(o.name);
}
}
訪問(wèn)屬性和方法有兩種方式,第一種:
alert(o.name);
o.showName();
這種寫(xiě)法很常見(jiàn),C#中調(diào)用對(duì)象的屬性和方法也是這種方式。還有一種是javascript中比較特別的,使用屬性或者方法的名字作為索引來(lái)進(jìn)行訪問(wèn):
alert(o["name"]);
o["showName"]();
這好像有點(diǎn)和孔乙己“茴香的茴字有幾種寫(xiě)法”差不多了,事實(shí)上,很少有人使用索引來(lái)調(diào)用對(duì)象的屬性或者方法。
除了我們自定義的屬性和方法,我們的對(duì)象還有一個(gè)constructor屬性以及toString()等方法。這些屬性和方法是從Object內(nèi)置對(duì)象來(lái)的,所有的對(duì)象都會(huì)有這些屬性和方法。其中constructor屬性指向構(gòu)造出該對(duì)象的構(gòu)造函數(shù)。我們沒(méi)有使用構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象,事實(shí)上,js的解釋器會(huì)使用Object構(gòu)造函數(shù)。如果我們自己定義了構(gòu)造函數(shù),那么便可以通過(guò)該構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象,這樣可以使得創(chuàng)建的對(duì)象具有相同的屬性和方法,這便開(kāi)始有點(diǎn)面向?qū)ο蟮奈兜懒?。好,我們從一個(gè)簡(jiǎn)單的例子開(kāi)始看看如何創(chuàng)建一個(gè)構(gòu)造函數(shù)吧:
function Person(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
this.showInfo = function() {
alert("姓名:" + this.name + " 性別:" + this.sex + " 年齡:" + this.age);
}
}
我們定義了一個(gè)名字叫Person的構(gòu)造函數(shù),該構(gòu)造函數(shù)有三個(gè)屬性和一個(gè)方法,通過(guò)構(gòu)造函數(shù)來(lái)產(chǎn)生一個(gè)對(duì)象并調(diào)用方法也非常簡(jiǎn)單:
var zhangsan = new Person("張三", "男", 18);
zhangsan.showInfo();
運(yùn)行后我們可以看到彈出一個(gè)對(duì)話框,顯示出這個(gè)叫張三的人的信息:

我們還可以看看對(duì)象的constructor屬性來(lái)看看zhangsan的構(gòu)造函數(shù)是不是我們定義好的Person:
alert(zhangsan.constructor);
結(jié)果如圖:

可以看到,正是我們的Person構(gòu)造函數(shù)。
不過(guò),這里還是有點(diǎn)問(wèn)題,每一次我們構(gòu)造一個(gè)對(duì)象,都會(huì)在內(nèi)存中為屬性和方法分配內(nèi)存空間,而事實(shí)上,所有的對(duì)象完全可以用同一個(gè)方法,并不需要有多個(gè)方法的副本,這樣有些浪費(fèi)內(nèi)存空間。既然意識(shí)到了這個(gè)問(wèn)題,讓我們來(lái)想想如何解決吧。一個(gè)很自然的想法是,既然我們只想為方法分配一次內(nèi)存空間,那么我們可以設(shè)置一個(gè)值用來(lái)標(biāo)識(shí)方法的內(nèi)存空間是否已經(jīng)分配,按照這個(gè)思路,我們將構(gòu)造函數(shù)做如下修改:
function Person(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
if (typeof Person._initialized == "undefined") {
this.showInfo = function() {
alert("姓名:" + this.name + " 性別:" + this.sex + " 年齡:" + this.age);
}
Person._initialized = true;
}
}
這里,我們用一個(gè)成員_initialized來(lái)指示是否已經(jīng)對(duì)方法進(jìn)行了內(nèi)存空間的分配。當(dāng)?shù)谝粋€(gè)對(duì)象構(gòu)造的時(shí)候_initialized未被定義,所以我們的判斷語(yǔ)句為真,這時(shí)會(huì)對(duì)方法進(jìn)行了定義并分配內(nèi)存空間,然后把_initialized的值設(shè)置為true,用以表明方法的內(nèi)存空間已經(jīng)分配了。第二個(gè)對(duì)象構(gòu)造的時(shí)候則不會(huì)再進(jìn)入判斷,因而也不會(huì)再一次分配內(nèi)存空間。似乎沒(méi)什么問(wèn)題,運(yùn)行一下看看,張三的信息依然正常顯示。雖然不辛苦,不過(guò)解決了一個(gè)小問(wèn)題,還是慶祝下吧,來(lái)盤(pán)回鍋肉,我要大快朵頤。還沒(méi)開(kāi)吃,一個(gè)叫李四的MM也想讓電腦彈出她的個(gè)人信息。OK,很簡(jiǎn)單,再構(gòu)造一個(gè)對(duì)象,然后調(diào)用showInfo方法就可以了:
var lisi = new Person("李四", "女", 28);
lisi.showInfo();
為了照顧MM,還把這段放在了張三的前邊。MM的信息正確顯示出來(lái)了,可是張三的資料不見(jiàn)了。這下張三不樂(lè)意了,排名放在MM后邊也罷了,但好歹得有名字啊。這可苦了我這編程人員,回鍋肉看來(lái)沒(méi)辦法吃了,先改bug吧。打開(kāi)firebug,看到MM的信息顯示之后出現(xiàn)錯(cuò)誤,提示為:zhangsan.showInfo is not a function。設(shè)置斷點(diǎn)看看,構(gòu)造zhangsi對(duì)象以后發(fā)現(xiàn)并沒(méi)有showInfo這個(gè)方法。原來(lái)showInfo方法雖然只有一個(gè),但是存在于第一個(gè)對(duì)象之中,第二個(gè)對(duì)象并不能訪問(wèn)。那么,究竟如何才能讓同一個(gè)構(gòu)造函數(shù)產(chǎn)生的對(duì)象共用同一個(gè)函數(shù)呢?javascript中的prototype給我們提供了這個(gè)功能。根據(jù)javascript的規(guī)范中描述,每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性用于實(shí)現(xiàn)繼承和屬性的共享。我們的showInfo方法也可以看作是一個(gè)屬性,該屬性指向一個(gè)函數(shù)的引用?,F(xiàn)在我們使用prototype來(lái)使得我們的方法可以共享,代碼的改動(dòng)很簡(jiǎn)單,把this.showInfo改成Person.prototype.showInfo就可以了,改動(dòng)之后的代碼如下:
function Person(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
if (typeof Person._initialized == "undefined") {
Person.prototype.showInfo = function() {
alert("姓名:" + this.name + " 性別:" + this.sex + " 年齡:" + this.age);
}
Person._initialized = true;
}
}
使用該構(gòu)造函數(shù)生成兩個(gè)對(duì)象:
var lisi = new Person("李四", "女", 28);
lisi.showInfo();
var zhangsan = new Person("張三", "男", 18);
zhangsan.showInfo();
運(yùn)行之后先顯示李四的信息,然后是張三的信息?,F(xiàn)在兩個(gè)人都滿意了,可惜我的回鍋肉已經(jīng)涼了
面向?qū)ο笫紫纫袑?duì)象。在javascript中創(chuàng)建一個(gè)對(duì)象非常簡(jiǎn)單:
復(fù)制代碼 代碼如下:
var o={};
這樣就產(chǎn)生了一個(gè)對(duì)象,我們可以很方便的給這個(gè)對(duì)象添加屬性和方法:
復(fù)制代碼 代碼如下:
o.name="object name";
o.showName=function(){
alert(o.name);
}
不過(guò)大多數(shù)人還是習(xí)慣把對(duì)象的屬性和方法放在定義對(duì)象的一對(duì){}里邊:
復(fù)制代碼 代碼如下:
var o = {
name: "object name",
showName: function() {
alert(o.name);
}
}
訪問(wèn)屬性和方法有兩種方式,第一種:
復(fù)制代碼 代碼如下:
alert(o.name);
o.showName();
這種寫(xiě)法很常見(jiàn),C#中調(diào)用對(duì)象的屬性和方法也是這種方式。還有一種是javascript中比較特別的,使用屬性或者方法的名字作為索引來(lái)進(jìn)行訪問(wèn):
復(fù)制代碼 代碼如下:
alert(o["name"]);
o["showName"]();
這好像有點(diǎn)和孔乙己“茴香的茴字有幾種寫(xiě)法”差不多了,事實(shí)上,很少有人使用索引來(lái)調(diào)用對(duì)象的屬性或者方法。
除了我們自定義的屬性和方法,我們的對(duì)象還有一個(gè)constructor屬性以及toString()等方法。這些屬性和方法是從Object內(nèi)置對(duì)象來(lái)的,所有的對(duì)象都會(huì)有這些屬性和方法。其中constructor屬性指向構(gòu)造出該對(duì)象的構(gòu)造函數(shù)。我們沒(méi)有使用構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象,事實(shí)上,js的解釋器會(huì)使用Object構(gòu)造函數(shù)。如果我們自己定義了構(gòu)造函數(shù),那么便可以通過(guò)該構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象,這樣可以使得創(chuàng)建的對(duì)象具有相同的屬性和方法,這便開(kāi)始有點(diǎn)面向?qū)ο蟮奈兜懒?。好,我們從一個(gè)簡(jiǎn)單的例子開(kāi)始看看如何創(chuàng)建一個(gè)構(gòu)造函數(shù)吧:
復(fù)制代碼 代碼如下:
function Person(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
this.showInfo = function() {
alert("姓名:" + this.name + " 性別:" + this.sex + " 年齡:" + this.age);
}
}
我們定義了一個(gè)名字叫Person的構(gòu)造函數(shù),該構(gòu)造函數(shù)有三個(gè)屬性和一個(gè)方法,通過(guò)構(gòu)造函數(shù)來(lái)產(chǎn)生一個(gè)對(duì)象并調(diào)用方法也非常簡(jiǎn)單:
復(fù)制代碼 代碼如下:
var zhangsan = new Person("張三", "男", 18);
zhangsan.showInfo();
運(yùn)行后我們可以看到彈出一個(gè)對(duì)話框,顯示出這個(gè)叫張三的人的信息:

我們還可以看看對(duì)象的constructor屬性來(lái)看看zhangsan的構(gòu)造函數(shù)是不是我們定義好的Person:
復(fù)制代碼 代碼如下:
alert(zhangsan.constructor);
結(jié)果如圖:

可以看到,正是我們的Person構(gòu)造函數(shù)。
不過(guò),這里還是有點(diǎn)問(wèn)題,每一次我們構(gòu)造一個(gè)對(duì)象,都會(huì)在內(nèi)存中為屬性和方法分配內(nèi)存空間,而事實(shí)上,所有的對(duì)象完全可以用同一個(gè)方法,并不需要有多個(gè)方法的副本,這樣有些浪費(fèi)內(nèi)存空間。既然意識(shí)到了這個(gè)問(wèn)題,讓我們來(lái)想想如何解決吧。一個(gè)很自然的想法是,既然我們只想為方法分配一次內(nèi)存空間,那么我們可以設(shè)置一個(gè)值用來(lái)標(biāo)識(shí)方法的內(nèi)存空間是否已經(jīng)分配,按照這個(gè)思路,我們將構(gòu)造函數(shù)做如下修改:
復(fù)制代碼 代碼如下:
function Person(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
if (typeof Person._initialized == "undefined") {
this.showInfo = function() {
alert("姓名:" + this.name + " 性別:" + this.sex + " 年齡:" + this.age);
}
Person._initialized = true;
}
}
這里,我們用一個(gè)成員_initialized來(lái)指示是否已經(jīng)對(duì)方法進(jìn)行了內(nèi)存空間的分配。當(dāng)?shù)谝粋€(gè)對(duì)象構(gòu)造的時(shí)候_initialized未被定義,所以我們的判斷語(yǔ)句為真,這時(shí)會(huì)對(duì)方法進(jìn)行了定義并分配內(nèi)存空間,然后把_initialized的值設(shè)置為true,用以表明方法的內(nèi)存空間已經(jīng)分配了。第二個(gè)對(duì)象構(gòu)造的時(shí)候則不會(huì)再進(jìn)入判斷,因而也不會(huì)再一次分配內(nèi)存空間。似乎沒(méi)什么問(wèn)題,運(yùn)行一下看看,張三的信息依然正常顯示。雖然不辛苦,不過(guò)解決了一個(gè)小問(wèn)題,還是慶祝下吧,來(lái)盤(pán)回鍋肉,我要大快朵頤。還沒(méi)開(kāi)吃,一個(gè)叫李四的MM也想讓電腦彈出她的個(gè)人信息。OK,很簡(jiǎn)單,再構(gòu)造一個(gè)對(duì)象,然后調(diào)用showInfo方法就可以了:
復(fù)制代碼 代碼如下:
var lisi = new Person("李四", "女", 28);
lisi.showInfo();
為了照顧MM,還把這段放在了張三的前邊。MM的信息正確顯示出來(lái)了,可是張三的資料不見(jiàn)了。這下張三不樂(lè)意了,排名放在MM后邊也罷了,但好歹得有名字啊。這可苦了我這編程人員,回鍋肉看來(lái)沒(méi)辦法吃了,先改bug吧。打開(kāi)firebug,看到MM的信息顯示之后出現(xiàn)錯(cuò)誤,提示為:zhangsan.showInfo is not a function。設(shè)置斷點(diǎn)看看,構(gòu)造zhangsi對(duì)象以后發(fā)現(xiàn)并沒(méi)有showInfo這個(gè)方法。原來(lái)showInfo方法雖然只有一個(gè),但是存在于第一個(gè)對(duì)象之中,第二個(gè)對(duì)象并不能訪問(wèn)。那么,究竟如何才能讓同一個(gè)構(gòu)造函數(shù)產(chǎn)生的對(duì)象共用同一個(gè)函數(shù)呢?javascript中的prototype給我們提供了這個(gè)功能。根據(jù)javascript的規(guī)范中描述,每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性用于實(shí)現(xiàn)繼承和屬性的共享。我們的showInfo方法也可以看作是一個(gè)屬性,該屬性指向一個(gè)函數(shù)的引用?,F(xiàn)在我們使用prototype來(lái)使得我們的方法可以共享,代碼的改動(dòng)很簡(jiǎn)單,把this.showInfo改成Person.prototype.showInfo就可以了,改動(dòng)之后的代碼如下:
復(fù)制代碼 代碼如下:
function Person(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
if (typeof Person._initialized == "undefined") {
Person.prototype.showInfo = function() {
alert("姓名:" + this.name + " 性別:" + this.sex + " 年齡:" + this.age);
}
Person._initialized = true;
}
}
使用該構(gòu)造函數(shù)生成兩個(gè)對(duì)象:
復(fù)制代碼 代碼如下:
var lisi = new Person("李四", "女", 28);
lisi.showInfo();
var zhangsan = new Person("張三", "男", 18);
zhangsan.showInfo();
運(yùn)行之后先顯示李四的信息,然后是張三的信息?,F(xiàn)在兩個(gè)人都滿意了,可惜我的回鍋肉已經(jīng)涼了
相關(guān)文章
javascript 面向?qū)ο缶幊?function也是類
function在javascript中用來(lái)創(chuàng)建函數(shù)或方法,但要想實(shí)現(xiàn)面向?qū)ο蠓绞降木幊?,類是不可或缺的角色之一,而且是主角?/div> 2009-09-09javascript最常用與實(shí)用的創(chuàng)建類的代碼
組合構(gòu)造函數(shù)模式和原型模式2010-08-08Javascript 面向?qū)ο?對(duì)象(Object)
Javascript 面向?qū)ο?對(duì)象(Object)2010-05-05javascript 設(shè)計(jì)模式之單體模式 面向?qū)ο髮W(xué)習(xí)基礎(chǔ)
單體是在腳本加載時(shí)創(chuàng)建的,能將一系列有關(guān)聯(lián)的變量和方法組織為一個(gè)邏輯單元,邏輯單元里面的內(nèi)容通過(guò)單一的變量進(jìn)行訪問(wèn),也是筆記基礎(chǔ)與常用的面向?qū)ο蟮亩x方法。2010-04-04XRegExp 0.2: Now With Named Capture
XRegExp 0.2: Now With Named Capture...2007-11-11JavaScript 面向?qū)ο蟮闹接谐蓡T和公開(kāi)成員
這節(jié)來(lái)說(shuō)下JavaScript的私有成員和公開(kāi)成員,雖然JavaScript沒(méi)有private和public關(guān)鍵字,但還是那句話——作為開(kāi)發(fā)人員我們要有面向?qū)ο蟮乃枷耄?2010-05-05最新評(píng)論