學JS必看JavaScript數(shù)據(jù)結(jié)構(gòu)深度剖析_第1頁
學JS必看JavaScript數(shù)據(jù)結(jié)構(gòu)深度剖析_第2頁
學JS必看JavaScript數(shù)據(jù)結(jié)構(gòu)深度剖析_第3頁
學JS必看JavaScript數(shù)據(jù)結(jié)構(gòu)深度剖析_第4頁
學JS必看JavaScript數(shù)據(jù)結(jié)構(gòu)深度剖析_第5頁
已閱讀5頁,還剩21頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

1、JavaScript以其強大靈活的特點,被廣泛運用于各種類型的網(wǎng)站上。一直以來都沒怎么好好學JS,只是略懂皮毛,看這篇文章時有讀PHP圣經(jīng)的感覺,作者深入淺出、生動形象地用各種實例給我們分析了JavaScript的數(shù)據(jù)結(jié)構(gòu),讓人有一種豁然開朗的感覺。全文如下:編程世界里只存在兩種基本元素,一個是數(shù)據(jù),一個是代碼。編程世界就是在數(shù)據(jù)和代碼千絲萬縷的糾纏中呈現(xiàn)出無限的生機和活力。數(shù)據(jù)天生就是文靜的,總想保持自己固有的本色;而代碼卻天生活潑,總想改變這個世界。你看,數(shù)據(jù)代碼間的關系與物質(zhì)能量間的關系有著驚人的相似。數(shù)據(jù)也是有慣性的,如果沒有代碼來施加外力,她總保持自己原來的狀態(tài)。而代碼就象能量,他存

2、在的唯一目的,就是要努力改變數(shù)據(jù)原來的狀態(tài)。在代碼改變數(shù)據(jù)的同時,也會因為數(shù)據(jù)的抗拒而反過來影響或改變代碼原有的趨勢。甚至在某些情況下,數(shù)據(jù)可以轉(zhuǎn)變?yōu)榇a,而代碼卻又有可能被轉(zhuǎn)變?yōu)閿?shù)據(jù),或許還存在一個類似E=MC2形式的數(shù)碼轉(zhuǎn)換方程呢。然而,就是在數(shù)據(jù)和代碼間這種即矛盾又統(tǒng)一的運轉(zhuǎn)中,總能體現(xiàn)出計算機世界的規(guī)律,這些規(guī)律正是我們編寫的程序邏輯。不過,由于不同程序員有著不同的世界觀,這些數(shù)據(jù)和代碼看起來也就不盡相同。于是,不同世界觀的程序員們運用各自的方法論,推動著編程世界的進化和發(fā)展。眾所周知,當今最流行的編程思想莫過于面向?qū)ο缶幊痰乃枷?。為什么面向?qū)ο蟮乃枷肽苎杆亠L靡編程世界呢?因為面向?qū)ο?/p>

3、的思想首次把數(shù)據(jù)和代碼結(jié)合成統(tǒng)一體,并以一個簡單的對象概念呈現(xiàn)給編程者。這一下子就將原來那些雜亂的算法與子程序,以及糾纏不清的復雜數(shù)據(jù)結(jié)構(gòu),劃分成清晰而有序的對象結(jié)構(gòu),從而理清了數(shù)據(jù)與代碼在我們心中那團亂麻般的結(jié)。我們又可以有一個更清晰的思維,在另一個思想高度上去探索更加浩瀚的編程世界了。回歸簡單JavaScript就要理解JavaScript,你得首先放下對象和類的概念,回到數(shù)據(jù)和代碼的本原。前面說過,編程世界只有數(shù)據(jù)和代碼兩種基本元素,而這兩種元素又有著糾纏不清的關系。是把數(shù)據(jù)和代碼都簡化到最原始的程度。JavaScript中的數(shù)據(jù)很簡潔的。這五種,而復雜數(shù)據(jù)只有一種,即簡單數(shù)據(jù)只有und

4、efined,null,boolean,number和stringobject。這就好比中國古典的樸素唯物思想,把世界最基本的元素歸為金木水火土,其他復雜的物質(zhì)都是由這五種基本元素組成。JavaScript中的代碼只體現(xiàn)為一種形式,就是function。注意:以上單詞都是小寫的,不要和Number,String,Object,Function等JavaScript內(nèi)置函數(shù)混淆了。要知道,JavaScript語言是區(qū)分大小寫的呀!任何一個JavaScript的標識、常量、變量和參數(shù)都只是unfined,null,bool,number,string,object和function類型中的一種,也

5、就typeof返回值表明的類型。除此之外沒有其他類型了。先說說簡單數(shù)據(jù)類型吧。undefined:代表一切未知的事物,啥都沒有,無法想象,代碼也就更無法去處理了。注意:typeof(undefined)返回也是undefined。可以將undefined賦值給任何變量或?qū)傩?,但并不意味了清除了該變量,反而會因此多了一個屬性。null:有那么一個概念,但沒有東西。無中似有,有中還無。雖難以想象,但已經(jīng)可以用代碼來處理了。注意:typeof(null)返回object,但null并非object,具有null值的變量也并非object。boolean:是就是,非就非,沒有疑義。對就對,錯就錯,絕對

6、明確。既能被代碼處理,也可以控制代碼的流程。number:線性的事物,大小和次序分明,多而不亂。便于代碼進行批量處理,也控制代碼的迭代和循環(huán)等。注意:typeof(NaN)和typeof(Infinity)都返回number。NaN參與任何數(shù)值計算的結(jié)構(gòu)都是NaN,而且NaN!=NaN。Infinity/Infinity=NaN。string:面向人類的理性事物,而不是機器信號。人機信息溝通,代碼據(jù)此理解人的意圖等等,都靠它了。簡單類型都不是對象,JavaScript沒有將對象化的能力賦予這些簡單類型。直接被賦予簡單類型常量值的標識符、變量和參數(shù)都不是一個對象。所謂“對象化”,就是可以將數(shù)據(jù)和

7、代碼組織成復雜結(jié)構(gòu)的能力。JavaScript中只有object類型和function類型提供了對象化的能力。沒有類object就是對象的類型。在JavaScript中不管多么復雜的數(shù)據(jù)和代碼,都可以組織成object形式的對象。但JavaScript卻沒有“類”的概念!對于許多面向?qū)ο蟮某绦騿T來說,這恐怕是JavaScript中最難以理解的地方。是啊,幾乎任何講面向?qū)ο蟮臅?第一個要講的就是“類”的概念,這可是面向?qū)ο蟮闹е?。這突然沒有了“類”,我們就象一下子沒了精神支柱,感到六神無主。看來,要放下對象和類,達到“對象本無根,類型亦無形”的境界確實是件不容易的事情啊。這樣,我們先來看一段J

8、avaScript程序:varlife=;for(life.age=1;life.age=3;life.age+)switch(life.age)case1:life.body=“卵細胞”;life.say=function()alert(this.age+this.body);break;case2:life.tail=“尾巴”;life.gill=“腮”;life.body=“蝌蚪”;life.say=function()alert(this.age+this.body+”-”+this.tail+”,”+this.gill);break;case3:deletelife.tail;del

9、etelife.gill;life.legs=“四條腿”;life.lung=“肺”;life.body=“青蛙”;life.say=function()alert(this.age+this.body+”-”+this.legs+”,”+this.lung);break;life.say();life,life誕生時只是一個光溜溜的對象,這段JavaScript程序一開始產(chǎn)生了一個生命對象沒有任何屬性和方法。在第一次生命過程中,它有了一個身體屬性body,并有了一個法,看起來是一個“卵細胞”。在第二次生命過程中,它又長出了“尾巴”say方“腮”,有了tail和gill屬性,顯然它是一個“蝌蚪

10、”。在第三次生命過程中,它的tail和gill屬性消失了,但又長出了“四條腿”和“肺”,有了legs和lung屬性,從而最終變成了“青蛙”。如果,你的想像力豐富的話,或許還能讓它變成英俊的“王子”,娶個美麗的“公主”什么的。不過,在看完這段程序之后,請你思考一個問題:我們一定需要類嗎?還記得兒時那個“小蝌蚪找媽媽”的童話嗎?也許就在昨天晚,你的孩子剛好是在這個美麗的童話中進入夢鄉(xiāng)的吧??蓯鄣男◎蝌揭簿褪窃谄渥陨眍愋筒粩嘌莼^程中,逐漸變成了和媽媽一樣的“類”,從而找到了自己的媽媽。這個童話故事中蘊含的編程哲理就是:對象的“類”是從無到有,又不斷演化,最終又消失于無形之中的“類”,的確可以幫助我

11、們理解復雜的現(xiàn)實世界,這紛亂的現(xiàn)實世界也的確需要進行分類。但如果我們的思想被“類”束縛住了,“類”也就變成了“累”。想象一下,如果一個生命對象開始的時就被規(guī)定了固定的“類”,那么它還能演化嗎?蝌蚪還能變成青蛙嗎?還可以給孩子們講小蝌蚪找媽媽的故事嗎?所以,JavaScript中沒有“類”,類已化于無形,與對象融為一體。正是由于放下了“類”JavaScript的禪機了。這個概念,JavaScript的對象才有了其他編程語言所沒有的活力。如果,此時你的內(nèi)心深處開始有所感悟,那么你已經(jīng)逐漸開始理解函數(shù)的魔力接下來,我們再討論一下JavaScript函數(shù)的魔力吧。JavaScript的代碼就只有言還有

12、procedure或我們寫下一個函數(shù)的時候,functionmyfunc()alert(”hello”);function一種形式,method等代碼概念,但在只不過是建立了一個function就是函數(shù)的類型。也許其他編程語JavaScript里只有function一種形式。當function類型的實體而已。請看下面的程序:alert(typeof(myfunc);這個代碼運行之后可以看到typeof(myfunc)返回的是“定義式”的,如果我們將其改寫成下面的“變量式”的,就更容易理解了:varmyfunc=function()alert(”hello”);alert(typeof(myfu

13、nc);function。以上的函數(shù)寫法我們稱之為這里明確定義了一個變量typeof(myfund)回的也是myfunc,它的初始值被賦予了一個function的實體。因此,function。其實,這兩種函數(shù)的寫法是等價的,除了一點細微差別,其內(nèi)部實現(xiàn)完全相同。也就是說,我們寫的這些JavaScript函數(shù)只是一個命了名的變量而已,其變量類型即為function,變量的值就是我們編寫的函數(shù)代碼體。聰明的你或許立即會進一步的追問:既然函數(shù)只是變量,那么變量就可以被隨意賦值并用到任意地方啰?我們來看看下面的代碼:varmyfunc=function()alert(”hello”);myfunc()

14、;/第一次調(diào)用myfunc,輸出hellomyfunc=function()alert(”yeah”);myfunc();/第二次調(diào)用myfunc,將輸出yeah這個程序運行的結(jié)果告訴我們:答案是肯定的!在第一次調(diào)用函數(shù)之后,函數(shù)變量又被賦予了新的函數(shù)代碼體,使得第二次調(diào)用該函數(shù)時,出現(xiàn)了不同的輸出。好了,我們又來把上面的代碼改成第一種定義式的函數(shù)形式:functionmyfunc()alert(”hello”);myfunc();/這里調(diào)用myfunc,輸出yeah而不是hellofunctionmyfunc()alert(”yeah”);myfunc();/這里調(diào)用myfunc,當然輸出y

15、eah按理說,兩個簽名完全相同的函數(shù),在其他編程語言中應該是非法的。但在JavaScript中,這沒錯。不過,程序運行之后卻發(fā)現(xiàn)一個奇怪的現(xiàn)象:兩次調(diào)用都只是最后那個函數(shù)里輸出的值!顯然第一個函數(shù)沒有起到任何作用。這又是為什么呢?原來,JavaScript執(zhí)行引擎并非一行一行地分析和執(zhí)行程序,而是一段一段地分析執(zhí)行的。而且,在同一段程序的分析執(zhí)行中,定義式的函數(shù)語句會被提取出來優(yōu)先執(zhí)行。函數(shù)定義執(zhí)行完之后,才會按順序執(zhí)行其他語句代碼。也就是說,在第一次調(diào)用myfunc之前,第一個函數(shù)語句定義的代碼邏輯,已被第二個函數(shù)定義語句覆蓋了。所以,兩次都調(diào)用都是執(zhí)行最后一個函數(shù)邏輯了。如果把這個Java

16、Script代碼分成兩段,例如將它們寫在一個html中,并用script/標簽將其分成這樣的兩塊:scriptfunctionmyfunc()alert(”hello”);myfunc();/DODOmyfunc,輸出hello/scriptscriptfunctionmyfunc()alert(”yeah”);myfunc();/DODOmyfunc,輸出yeah這時,輸出才是各自按順序來的,也證明了JavaScript的確是一段段地執(zhí)行的。一段代碼中的定義式函數(shù)語句會優(yōu)先執(zhí)行,這似乎有點象靜態(tài)語言的編譯概念。所以,這一特征也被有些人稱為:JavaScript的“預編譯”。JavaScrip

17、t里的代大多數(shù)情況下,我們也沒有必要去糾纏這些細節(jié)問題。只要你記住一點:碼也是一種數(shù)據(jù),同樣可以被任意賦值和修改的,而它的值就是代碼的邏輯。只是,與一般數(shù)據(jù)不同的是,函數(shù)是可以被調(diào)用執(zhí)行的。不過,如果JavaScript函數(shù)僅僅只有這點道行的話,這與C+的函數(shù)指針,DELPHI的方法指針,C#的委托相比,又有啥稀奇嘛!然而,JavaScript函數(shù)的神奇之處還體現(xiàn)在另外兩個方面:一是函數(shù)function類型本身也具有對象化的能力,二是函數(shù)function與對象object超然的結(jié)合能力。奇妙的對象先來說說函數(shù)的對象化能力。任何一個函數(shù)都可以為其動態(tài)地添加或去除屬性,這些屬性可以是簡單類型,可以

18、是對象,也可以是其他函數(shù)。也就是說,函數(shù)具有對象的全部特征,你完全可以把函數(shù)當對象來用。其實,函數(shù)就是對象,只不過比一般的對象多了一個括號“()”操作符,這個操作符用來執(zhí)行函數(shù)的邏輯。即,函數(shù)本身還可以被調(diào)用,一般對象卻不可以被調(diào)用,除此之外完全相同。請看下面的代碼:functionSing()with(arguments.callee)alert(author+“:”+poem);TOC o 1-5 h zSing.author=“李白”;Sing.poem=“漢家秦地月,流影照明妃。一上玉關道,天涯去不歸”;Sing();Sing.author=“李戰(zhàn)”;Sing.poem=“日出漢家天,

19、月落陰山前。女兒琵琶怨,已唱三千年”;在這段代碼中,Sing函數(shù)被定義后,又給author和poem屬性設為不同的作者和詩句,在調(diào)用示例用一種詩情畫意的方式,讓我們理解了Sing();Sing函數(shù)動態(tài)地增加了author和poem屬性。將Sing()時就能顯示出不同的結(jié)果。這個JavaScript函數(shù)就是對象的本質(zhì),也感受到了JavaScript語言的優(yōu)美。好了,以上的講述,我們應該算理解了function類型的東西都是和object類型一樣的東西,這種東西被我們稱為“對象”。我們的確可以這樣去看待這些“對象”,因為它們既有“屬性”也有“方法”嘛。但下面的代碼又會讓我們產(chǎn)生新的疑惑:varan

20、Object=;/一個對象anObject.aProperty=“Propertyofobject”;/對象的一個屬性anObject.aMethod=function()alert(”Methodofobject”);/對象的一個方法/主要看下面:alert(anObject”aProperty”);/可以將對象當數(shù)組以屬性名作為下標來訪問屬性anObject”aMethod”();/可以將對象當數(shù)組以方法名作為下標來調(diào)用方法for(varsinanObject)/遍歷對象的所有屬性和方法進行迭代化處理alert(s+”isa”+typeof(anObjects);同樣對于function類

21、型的對象也是一樣:varaFunction=function();/一個函數(shù)aFunction.aProperty=“Propertyoffunction”;/函數(shù)的一個屬性aFunction.aMethod=function()alert(”Methodoffunction”);/函數(shù)的一個方法/主要看下面:alert(aFunction”aProperty”);/可以將函數(shù)當數(shù)組以屬性名作為下標來訪問屬性aFunction”aMethod”();/可以將函數(shù)當數(shù)組以方法名作為下標來調(diào)用方法for(varsinaFunction)/遍歷函數(shù)的所有屬性和方法進行迭代化處理alert(s+”is

22、a”+typeof(aFunctions);是的,對象和函數(shù)可以象數(shù)組一樣,用屬性名或方法名作為下標來訪問并處理。那么,它到底應該算是數(shù)組呢,還是算對象?我們知道,數(shù)組應該算是線性數(shù)據(jù)結(jié)構(gòu),線性數(shù)據(jù)結(jié)構(gòu)一般有一定的規(guī)律,適合進行統(tǒng)一的批量迭代操作等,有點像波。而對象是離散數(shù)據(jù)結(jié)構(gòu),適合描述分散的和個性化的東西,有點像粒子。因此,我們也可以這樣問:JavaScript里的對象到底是波還是粒子?如果存在對象量子論,那么答案一定是:波粒二象性!因此,JavaScript里的函數(shù)和對象既有對象的特征也有數(shù)組的特征。這里的數(shù)組被稱為“字典”,一種可以任意伸縮的名稱值對兒的集合。其實,object和fun

23、ction的內(nèi)部實現(xiàn)就是一個字典結(jié)構(gòu),但這種字典結(jié)構(gòu)卻通過嚴謹而精巧的語法表現(xiàn)出了豐富的外觀。正如量子力學在一些地方用粒子來解釋和處理問題,而在另一些地方卻用波來解釋和處理問題。你也可以在需要的時候,自由選擇用對象還是數(shù)組來解釋和處理問題。只要善于把握JavaScript的這些奇妙特性,就可以編寫出很多簡潔而強大的代碼來。放下對象我們再來看看function與object的超然結(jié)合吧。在面向?qū)ο蟮木幊淌澜缋铮瑪?shù)據(jù)與代碼的有機結(jié)合就構(gòu)成了對象的概念。自從有了對象,編程世界就被劃分成兩部分,一個是對象內(nèi)的世界,一個是對象外的世界。對象天生具有自私的一面,外面的世界未經(jīng)允許是不可訪問對象內(nèi)部的。對象

24、也有大方的一面,它對外提供屬性和方法,也為他人服務。不過,在這里我們要談到一個有趣的問題,就是“對象的自我意識”。什么?沒聽錯吧?對象有自我意識?可能對許多程序員來說,這的確是第一次聽說。不過,請君看看C+、C#和Java的this,DELPHI的self,還有VB的me,或許你會恍然大悟!當然,也可能只是說句“不過如此”而已。也就隨之產(chǎn)生?!白晕乙庾R”然而,就在對象將世界劃分為內(nèi)外兩部分的同時,對象的“自我”是生命的最基本特征!正是由于對象這種強大的生命力,才使得編程世界充滿無限的生機和活力。但對象的“自我意識”在帶給我們快樂的同時也帶來了痛苦和煩惱。我們給對象賦予了太多欲望,總希望它們能做

25、更多的事情。然而,對象的自私使得它們互相爭搶系統(tǒng)資源,對象的自負讓對象變得復雜和臃腫,對象的自欺也往往帶來揮之不去的錯誤和異常。我們?yōu)槭裁磿羞@么多的痛苦和煩惱呢?JavaScript中也有this,但這個this卻與C+、C#或Java等語言的this不同。一般編程語言的this就是對象自己,而JavaScript的this卻并不一定!你,可能是他,反正是我中有你,你中有我,這就不能用原來的那個this可能是我,也可能是“自我”來理解JavaScript為此,有一個人,在對象樹下,整整想了九九八十一天,終于悟出了生命的痛苦來自于欲望,但究其欲望的根源是來自于自我意識。于是他放下了“自我”,在

26、對象樹下成了佛,從此他開始普度眾生,傳播真經(jīng)。他的名字就叫釋迦摩尼,而JavaScript真經(jīng)正是他所傳經(jīng)書中的一本。這個this的含義了。為此,我們必須首先放下原來對象的那個“自我”我們來看下面的代碼:functionWhoAmI()/定義一個函數(shù)WhoAmIalert(”Im”+”of”+typeof(this);this當前這段代碼的全局對象,在瀏覽器中就是Imofobjectwindow對象,其nameWhoAmI();/此時是屬性為空字符串。輸出:varBillGates=name:“BillGates”;BillGates.WhoAml=WhoAmI;/將函數(shù)WhoAmI作為Bil

27、lGates的方法。BillGates.WhoAmI();/此時的this是BillGates。輸出:ImBillGatesofobjectvarSteveJobs=name:“SteveJobs”;SteveJobs.WhoAml=WhoAmI;/將函數(shù)WhoAmI作為Stevejobs的方法。Stevejobs.WhoAmI();/此時的this是Stevejobs。輸出:ImSteveJobsofobjectWhoAmI.call(BillGates);/直接將BillGates作為this,DOWhoAmI。輸出:ImBillGatesofobjectWhoAmI.call(Steve

28、jobs);/直接將Stevejobs作為this,DOWhoAmI。輸出:ImStevejobsofobjectBillGates的WhoAmIStevejobs的WhoAmIBillGates.WhoAmI.call(Stevejobs);/將Stevejobs作為this,ODO方法。輸出:ImStevejobsofobjectStevejobs.WhoAmI.call(BillGates);/將BillGates作為this,ODO方法。輸出:ImBillGatesofobjectWhoAmI.WhoAmI=WhoAmI;/將WhoAmI函數(shù)設置為自身的方法。WhoAmI.name=“

29、WhoAmI”;ImWhoAmIoffunctionWhoAmI.WhoAmI();/此時的this是WhoAmI函數(shù)自己。輸出:(name:“nobody”,DOWhoAmI方法。輸出:WhoAmI:WhoAmI).WhoAmI();/臨時創(chuàng)建一個匿名對象并設置屬性后Imnobodyofobject從上面的代碼可以看出,同一個函數(shù)可以從不同的角度來調(diào)O,this并不一定是函數(shù)本身所屬的對象。this只是在任意對象和function元素結(jié)合時的一個概念,是種結(jié)合比起一般對象語言的默認結(jié)合更加靈活,顯得更加超然和灑脫。在javaScript函數(shù)中,你只能把this看成當前要服務的“這個”對象。t

30、his是一個特殊的0000,00this參數(shù),您可以訪問到“這個”對象的屬性和方法,但卻不能給this參數(shù)賦值。在一般對象語言中,方法體代碼中的this00000,成員默認都首先是“自己”this不000!已經(jīng)說了許多了許多話題了,但有一個很基本0問題我們忘了討論,那就是:怎樣建立對象?在前面0示例中,我們已經(jīng)涉及到了對象的建立了。我們使用了一種被稱為javaScriptObjectNotation(縮寫jSON)的形式,翻譯為中文就是“javaScript對象表示法”jSON為創(chuàng)建對象提供了非常簡單0方法。例如,創(chuàng)建一個沒有任何屬性0對象:javaScript提供了傳遞this參數(shù)0多種形式

31、和手段,其中,象Stevejobs.WhoAmI()這種形式,是傳遞this參數(shù)最正規(guī)的形式,此時0BillGates.WhoAmI()和this就是函數(shù)所屬0。但javaScript卻不同,由于不存在“自我”,當訪問“這個”對象時,的對象本身。而大多數(shù)情況下,我們也幾乎很少去采用那些借花仙佛0DO形式。但只我們要明白javaScript的這個“自我”與其他編程語言0“自我”是不同0,這是一個放下了的“自我”,這就是javaScript特有的世界觀。對象素描varo=;創(chuàng)建一個對象并設置屬性及初始值:varperson=name:“Angel”,age:18,married:false;創(chuàng)建一

32、個對象并設置屬性和方法:varspeaker=text:“HelloWorld”,say:function()alert(this.text);創(chuàng)建一個更復雜的對象,嵌套其他對象和對象數(shù)組等:varcompany=name:“Microsoft”,product:“softwares”,chairman:name:“BillGates”,age:53,Married:true,employees:name:“Angel”,age:26,Married:false,name:“Hanson”,age:32,Marred:true,readme:function()document.write(+

33、”product”+duct);JSON的形式就是用大括“”號包括起來的項目列表,每一個項目間并用逗號“,”分隔,而項目就是用冒號“:”分隔的屬性名和屬性值。這是典型的字典表示形式,也再次表明了JavaScript里的對象就是字典結(jié)構(gòu)。不管多么復雜的對象,都可以被一句JSON代碼來創(chuàng)建并賦值。其實,JSON就是JavaScript對象最好的序列化形式,它比XML更簡潔也更省空間。對象可以作為一個JSON形式的字符串,在網(wǎng)絡間自由傳遞和交換信息。而當需要將這個JSON字符串變成一個JavaScript對象時,只需要使用eval函數(shù)這個強大的數(shù)碼轉(zhuǎn)換引擎,就立即能得到一個JavaScript內(nèi)存對

34、象。正是由于JSON的這種簡單樸素的天生麗質(zhì),才使得她在AJAX舞臺上成為璀璨奪目的明星。JavaScript就是這樣,把面向?qū)ο竽切┛此茝碗s的東西,用及其簡潔的形式表達出來。卸下對象浮華的濃妝,還對象一個眉目清晰!構(gòu)造對象好了,接下我們來討論一下對象的另一種創(chuàng)建方法。除JSON外,在JavaScript中我們可以使用new操作符結(jié)合一個函數(shù)的形式來創(chuàng)建對象。例如:functionMyFunc();/定義一個空函數(shù)varanObj=newMyFunc();/使用new操作符,借助MyFun函數(shù),就創(chuàng)建了一個對象JavaScript的這種創(chuàng)建對象的方式可真有意思,如何去理解這種寫法呢?其實,可以

35、把上面的代碼改寫成這種等價形式:functionMyFunc();varanObj=;/創(chuàng)建一個對象MyFunc.call(anObj);/將anObj對象作為thisODDOMyFunc函數(shù)我們就可以這樣理解,JavaScript先用new操作符創(chuàng)建了一個對象,緊接著就將這個對象作為this參數(shù)調(diào)用了后面的函數(shù)。其實,JavaScript內(nèi)部就是這么做的,而且任何函數(shù)都可以被這樣調(diào)用!但從“anObj=newMyFunc()”這種形式,我們又看到一個熟悉的身影,C+和C#不就是這樣創(chuàng)建對象的嗎?原來,條條大路通靈山,殊途同歸啊!君看到此處也許會想,我們?yōu)槭裁床豢梢园堰@個MyFunc當作構(gòu)造函

36、數(shù)呢?恭喜你,答對了!JavaScript也是這么想的!請看下面的代碼:functionPerson(name)/帶參數(shù)的構(gòu)造函數(shù)=name;/將參數(shù)值賦給給this對象的屬性this.SayHello=function()alert(”Hello,Im”+);/給this對象定義一個SayHello方法。;functionEmployee(name,salary)/子構(gòu)造函數(shù)Person.call(this,name);/將this傳給父構(gòu)造函數(shù)this.salary=salary;/設置一個this的salary屬性this.ShowMeTheMoney=function()alert(+

37、”$”+this.salary);/添加ShowMeTheMoney方法。;varBillGates=newPerson(DBillGates”);/用Person構(gòu)造函數(shù)創(chuàng)建BillGates對象varSteveJobs=newEmployee(DSteveJobsD,1234);/OEmpolyee構(gòu)造函數(shù)創(chuàng)建SteveJobs象BillGates.SayHello();/顯示:ImBillGatesSteveJobs.SayHello();/顯示:ImSteveJobsSteveJobs.ShowMeTheMoney();/顯示:SteveJobs$1234alert(BillGates

38、.constructor=Person);/顯示:truealert(SteveJobs.constructor=Employee);/顯示:truealert(BillGates.SayHello=SteveJobs.SayHello);/顯示:false這段代碼表明,函數(shù)不但可以當作構(gòu)造函數(shù),而且還可以帶參數(shù),還可以為對象添加成員和方法。其中的第9行,Employee構(gòu)造函數(shù)又將自己接收的this作為參數(shù)調(diào)用PersonD00數(shù),這就是相當于調(diào)用基類的構(gòu)造函數(shù)。第21、22行還表明這樣一個意思:BillGates是由Person構(gòu)造的,而SteveJobs是由Employee構(gòu)造的。對象內(nèi)

39、置的constructor屬性還指明了構(gòu)造對象所用的具體函數(shù)!“類”的那些特征。其實,如果你愿意把函數(shù)當作“類”的話,她就是“類”,因為她本來就有難道不是嗎?她生出的兒子各個都有相同的特征,而且構(gòu)造函數(shù)也與類同名嘛!不但具有各自的成員數(shù)據(jù),(體現(xiàn)函數(shù)邏輯的數(shù)據(jù))在每一個對象JavaScript中的函數(shù)就是對象的概但要注意的是,用構(gòu)造函數(shù)操作this對象創(chuàng)建出來的每一個對象,而且還具有各自的方法數(shù)據(jù)。換句話說,方法的代碼體中都存在一個副本。盡管每一個代碼副本的邏輯是相同的,但對象們確實是各自保存了一份代碼體。上例中的最后一句說明了這一實事,這也解釋了念。同一類的對象各自有一份方法代碼顯然是一種浪

40、費。在傳統(tǒng)的對象語言中,方法函數(shù)并不象JavaScript那樣是個對象概念。即使也有象函數(shù)指針、方法指針或委托那樣的變化形式,但其實質(zhì)也是對同一份代碼的引用。一般的對象語言很難遇到這種情況。不過,JavaScript語言有大的靈活性。我們可以先定義一份唯一的方法函數(shù)體,并在構(gòu)造this對象時使用這唯一的函數(shù)對象作為其方法,就能共享方法邏輯。例如:functionSayHello()/先定義一份SayHello函數(shù)代碼alert(”Hello,Im”+);functionPerson(name)/帶參數(shù)的構(gòu)造函數(shù)=name;/將參數(shù)值賦給給this對象的屬性this.SayHello=SayHe

41、llo;/給this對象SayHello方法賦值為前面那份SayHelloODD;BillGates對象varBillGates=newPerson(”BillGates”);/創(chuàng)建varSteveJobs=newPerson(SteveJobs”);/創(chuàng)建SteveJobs對象alert(BillGates.SayHello=SteveJobs.SayHello);/顯示:true其中,最后一行的輸出結(jié)果表明兩個對象確實共享了一個函數(shù)對象。雖然,這段程序達到了共享了一份方法代碼的目的,但卻不怎么優(yōu)雅。因為,定義Person類的關系。“優(yōu)雅”這個詞用來形容代碼,也不知道是誰先提出來的。不過,這

42、個詞反映了程序員已經(jīng)從追求代碼的正確、高效、可靠和易讀等基礎上,向著追求代碼的美觀感覺和藝術境界的層次發(fā)展,程序人生又多了些浪漫色彩。顯然,JavaScript早想到了這一問題,她的設計者們?yōu)榇颂峁┝艘粋€有趣的SayHello方法時反映不出其與prototype概念。初看原型prototype源自法語,軟件界的標準翻譯為“原型”,代表事物的初始形態(tài),也含有模型和樣板的意義。JavaScript中的prototype概念恰如其分地反映了這個詞的內(nèi)含,理解為C+的prototype那種預先聲明的概念。我們不能將其JavaScript的所有function類型的對象都有一個prototype屬性。這

43、個prototype屬性本身又是一個object類型的對象,法。既然prototype是對象的型”的特性。事實上,在構(gòu)造函數(shù)的構(gòu)造的對象直接訪問和調(diào)用的。方法的機制。因此我們也可以給這個prototype對象添加任意的屬性和方“原“原型”,那么由該函數(shù)構(gòu)造出來的對象應該都會具有這個prototype上定義的所有屬性和方法,都是可以通過其也可以這么說,prototype提供了一群同類對象共享屬性和我們先來看看下面的代碼:functionPerson(name)=name;/設置對象屬性,每個對象各自一份屬性數(shù)據(jù);Ptotype.SayHello=function()/給Person函數(shù)的prot

44、otype00SayHello方法。alert(”Hello,Im”+);varBillGates=newPerson(”BillGates”);/創(chuàng)建varSteveJobs=newPerson(SteveJobs”);/創(chuàng)建BillGates對象SteveJobs對象BillGates.SayHello();/SteveJobs.SayHello();/通過BillGates對象直接調(diào)用到通過SteveJobs對象直接調(diào)用到SayHello方法SayHello方法prototypealert(BillGates.SayHello=SteveJobs.SayHello);/因為兩個對象是共享

45、的SayHello所以顯示:true程序運行的結(jié)果表明,構(gòu)造函數(shù)的prototype上定義的方法確實可以通過對象直接調(diào)用到,而且代碼是共享的。顯然,把方法設置到prototype的寫法顯得優(yōu)雅多了,盡管調(diào)用形式?jīng)]有變,但邏輯上卻體現(xiàn)了方法與類的關系,相對前面的寫法,更容易理解和組織代碼。那么,對于多層次類型的構(gòu)造函數(shù)情況又如何呢?我們再來看下面的代碼:functionPerson(name)/基類構(gòu)造函數(shù)=name;prototype0000Ptotype.SayHello=function()/給基類構(gòu)造函數(shù)的alert(”Hello,Im”+);functionEmployee(name,

46、salary)/子類構(gòu)造函數(shù)Person.call(this,name);/調(diào)用基類構(gòu)造函數(shù)this.salary=salary;Etotype=newPerson();/建一個基類的對象作為子類原型的原型,這里很有意思Etotype.ShowMeTheMoney=function()/給子類添構(gòu)造函數(shù)的prototype添加方法alert(+”$”+this.salary);varBillGates=newPerson(”BillGates”);/創(chuàng)建基類Person的BillGates對象varSteveJobs=newEmployee”SteveJobs”,1234);/創(chuàng)建子類Empl

47、oyee的SteveJobs對象BillGates.SayHello();/通過對象直接調(diào)用到prototype的方法SteveJobs.SayHello();/通過子類對象直接調(diào)用基類prototype的方法,關注!SteveJobs.ShowMeTheMoney();/通過子類對象直接調(diào)用子類prototype000alert(BillGates.SayHello=SteveJobs.SayHello);/DO:true,表明prototype00法是共享的這段代碼的第17行,構(gòu)造了一個基類的對象,并將其設為子類構(gòu)造函數(shù)0prototype,這是很有意思0。這樣做0目0就是為了第28行,通

48、過子類對象也可以直接調(diào)用基類prototype00法。為什么可以這樣呢?prototype還有尋根原來,在JavaScript中,prototype不但能讓對象共享自己財富,而且問祖0天性,從而使得先輩們0遺產(chǎn)可以代代相傳。當從一個對象那里讀取屬性或調(diào)用0法時,如果該對象自身不存在這樣0屬性或0法,如果prototype沒有,又會去追溯過程結(jié)束為止。就會去自己關聯(lián)0prototype自己關聯(lián)的前輩prototype對象那里尋找;prototype那里尋找,直到找到或當用(如在JavaScript內(nèi)部,對象0屬性和0法追溯機制是通過所謂0prototype鏈來實現(xiàn)0。new操作符構(gòu)造對象時,也會

49、同時將構(gòu)造函數(shù)的prototype對象指派給新創(chuàng)建的對象,成為該對象內(nèi)置0原型對象。對象內(nèi)置0原型對象應該是對外不可見0,盡管有些瀏覽器Firefox)以讓我們訪問這個內(nèi)置原型對象,但并不建議這樣做。內(nèi)置的原型對象本身也是對象,也有自己關聯(lián)的原型對象,這樣就形成了所謂的原型鏈。在原型鏈的最末端,就是Object構(gòu)造函數(shù)prototype屬性指向的那一個原型對象。這個原型對象是所有對象的最老祖先,這個老祖宗實現(xiàn)了諸如toString等所有對象天生就該具有的方法。其他內(nèi)置構(gòu)造函數(shù),如Function,Boolean,String,Date和RegExp等的prototype都是從這個老祖宗傳承下來

50、的,但他們各自又定義了自身的屬性和方法,從而他們的子孫就表現(xiàn)出各自宗族的那些特征。這不就是“繼承”嗎?是的,這就是“繼承”,是JavaScript特有的“原型繼承”“原型繼承”是慈祥而又嚴厲的。原形對象將自己的屬性和方法無私地貢獻給孩子們使用,也并不強迫孩子們必須遵從,允許一些頑皮孩子按自己的興趣和愛好獨立行事。從這點上看,原型對象是一位慈祥的母親。然而,任何一個孩子雖然可以我行我素,但卻不能動原型對象既有的財產(chǎn),因為那可能會影響到其他孩子的利益。從這一點上看,原型對象又象一位嚴厲的父親。我們來看看下面的代碼就可以理解這個意思了:functionPerson(name)=name;Ppany=

51、“Microsoft”;/原型的屬性Ptotype.SayHello=function()/原型的方法alert(”Hello,Im”+”of”+pany);varBillGates=newPerson(”BillGates”);Hello,ImBillGatesBillGates.SayHello();/由于繼承了原型的東西,規(guī)規(guī)矩矩輸出:varSteveJobs=newPerson”(SteveJobs”);company屬性,掩蓋了原型的SayHello方法,掩蓋了原型的company屬性SayHelloSteveJpany=“Apple”;/設置自己的SteveJobs.SayHell

52、o=function()/實現(xiàn)了自己的方法alert(”Hi,+”like+pany+“,hahaha“);Hi,SteveJobslikeApple,BillGates還是按老樣子輸;SteveJobs.SayHello();/都是自己覆蓋的屬性和方法,輸出:hahahaBillGates.SayHello();/Stevejobs的覆蓋沒有影響原型對象,出對象可以掩蓋原型對象的那些屬性和方法,一個構(gòu)造函數(shù)原型對象也可以掩蓋上層構(gòu)造函數(shù)原型對象既有的屬性和方法。這種掩蓋其實只是在對象自己身上創(chuàng)建了新的屬性和方法,只不過這些屬性和方法與原型對象的那些同名而已。JavaScript就是用這簡單的

53、掩蓋機制實現(xiàn)了對象的“多態(tài)”性,與靜態(tài)對象語言的虛函數(shù)和重載(override)概念不謀而合。然而,比靜態(tài)對象語言更神奇的是,我們可以隨時給原型對象動態(tài)添加新的屬性和方法,從而動態(tài)地擴展基類的功能特性。這在靜態(tài)對象語言中是很難想象的。我們來看下面的代碼:functionPerson(name)=name;Ptotype.SayHello=function()/建立對象前定義的方法alert(”Hello,Im”+);varBillGates=newPerson(”BillGates”);/建立對象BillGates.SayHello();Ptotype.Retire=function()/建立

54、對象后再動態(tài)擴展原型的方法alert(”Poor”+“,byebye!”);BillGates.Retire();/動態(tài)擴展的方法即可被先前建立的對象立即調(diào)用阿彌佗佛,原型繼承竟然可以玩出有這樣的法術!原型擴展想必君的悟性極高,可能你會這樣想:如果在JavaScript內(nèi)置的那些如Object和Function等函數(shù)的prototype上添加些新的方法和屬性,是不是就能擴展JavaScript的功能呢?那么,恭喜你,你得到了!在AJAX技術迅猛發(fā)展的今天,函數(shù)的prototype功能。了大量的新特性,從而增強了許多成功的AJAX項目的JavaScript運行庫都大量擴展了內(nèi)置比如微軟的ASP.

55、NETAJAX,就給這些內(nèi)置函數(shù)及其prototype添加JavaScript的功能。我們來看一段摘自MicrosoftAjax.debug.js中的代碼:Stotype.trim=functionString$trim()if(arguments.length!=0)throwError.parameterCount();returnthis.replace(廠s+|s+$/g,”);String除非“類”DOODOODOOString函數(shù)的prototype擴展了一個trim方法,于是所有的類對象都有了trim方法了。有了這個擴展,今后要去除字符串兩段的空白,就不用再分別處理了,因為任何字

56、符串都有了這個擴展功能,只要調(diào)用即可,真的很方便。當然,幾乎很少有人去給Object的prototype添加方法,因為那會影響到所有的對象,在你的架構(gòu)中這種方法的確是所有對象都需要的。前兩年,微軟在設計AJAX類庫的初期,用了一種被稱為“閉包”(closure)的技術來模擬其大致模型如下:functionPerson(firstName,lastName,age)/私有變量:var_firstName=firstName;var_lastName=lastName;/公共變量:this.age=age;/方法:this.getName=function()return(firstName+”+

57、lastName);this.SayHello=function()alert(”Hello,Im”+firstName+”+lastName);varBillGates=newPerson(”Bill”,“Gates”,53);varSteveJobs=newPerson(”Steve”,“Jobs”,53);BillGates.SayHello();SteveJobs.SayHello();alert(BillGates.getName()+”+BillGates.age);alert(BillGates.firstName);/這里不能訪問到私有變量很顯然,這種模型的類描述特別象C#語言

58、的描述形式,在一個構(gòu)造函數(shù)里依次定義了私有成員、公共屬性和可用的方法,顯得非常優(yōu)雅嘛。特別是“閉包”機制可以模擬對私有成員的保護機制,做得非常漂亮。而這個對象這種間接所謂的“閉包”,就是在構(gòu)造函數(shù)體內(nèi)定義另外的函數(shù)作為目標對象的方法函數(shù),的方法函數(shù)反過來引用外層外層函數(shù)體中的臨時變量。這使得只要目標對象在生存期內(nèi)始終能保持其方法,就能間接保持原構(gòu)造函數(shù)體當時用到的臨時變量值。盡管最開始的構(gòu)造函數(shù)調(diào)用已經(jīng)結(jié)束,臨時變量的名稱也都消失了,但在目標對象的方法內(nèi)卻始終能引用到該變量的值,而且該值只能通這種方法來訪問。即使再次調(diào)用相同的構(gòu)造函數(shù),但只會生成新對象和方法,新的臨時變量只是對應新的值,和上次

59、那次調(diào)用的是各自獨立的。的確很巧妙!但是前面我們說過,給每一個對象設置一份方法是一種很大的浪費。還有,“閉包”保持變量值的機制,往往會給JavaSript的垃圾回收器制造難題。特別是遇到對象間復雜的循環(huán)引用時,垃圾回收的判斷邏輯非常復雜。無獨有偶,IE瀏覽器早期版本確實存在JavaSript圾回收方面的內(nèi)存泄漏問題。再加上“閉包”模型在性能測試方面的表現(xiàn)不佳,微軟最終放棄了“閉包”模型,而改用“原型”模型。正所謂“有得必有失”嘛。原型模型需要一個構(gòu)造函數(shù)來定義對象的成員,而方法卻依附在該構(gòu)造函數(shù)的原型上。大致寫法如下:/定義構(gòu)造函數(shù)functionPerson(name)=name;/在構(gòu)造函

60、數(shù)中定義成員;/方法定義到構(gòu)造函數(shù)的prototype上Ptotype.SayHello=function()alert(”Hello,Im”+);/子類構(gòu)造函數(shù)functionEmployee(name,salary)Person.call(this,name);/調(diào)用上層構(gòu)造函數(shù)this.salary=salary;/擴展的成員;/子類構(gòu)造函數(shù)首先需要用上層構(gòu)造函數(shù)來建立prototype對象,實現(xiàn)繼承的概念Etotype=newPerson()/只需要其prototype的方法,此對象的成員沒有任何意義!/子類方法也定義到構(gòu)造函數(shù)之上Etotype.ShowMeTheMoney=func

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論