關(guān)于函數(shù) 在Javascript中函數(shù)實(shí)際上就是一個(gè)對(duì)象,具有引用類型的特征,所以你可以將函數(shù)直接傳遞給變量,這個(gè)變量將表示指向函數(shù)“對(duì)象"的指針,例如:
你也可以直接將函數(shù)申明賦值給變量:
在這種情況下,函數(shù)申明中可以省略函數(shù)名稱,因?yàn)榇藭r(shí)名稱已經(jīng)沒有任何意義,我們可直接通過變量f來調(diào)用函數(shù)。 通過Function類型,我們可以更好地理解函數(shù)即對(duì)象:
關(guān)于this this可以看成調(diào)用函數(shù)的實(shí)際作用域上下文。比較以下函數(shù)的執(zhí)行結(jié)果:
定義類型 在Javascript中可以定義構(gòu)造函數(shù),構(gòu)造函數(shù)與一般函數(shù)沒有任何區(qū)別,在創(chuàng)建實(shí)例時(shí),如果我們使用了new關(guān)鍵字,那么這個(gè)函數(shù)就具有構(gòu)造函數(shù)的特性,否則就是一般函數(shù),如下所示,我們定義了一個(gè)Person類型:
當(dāng)使用new關(guān)鍵字時(shí),可以創(chuàng)建一個(gè)新的Person對(duì)象實(shí)例:
如果不使用new關(guān)鍵字,將直接執(zhí)行Person函數(shù),由于執(zhí)行上下文為全局范圍,故name屬性和Say方法將被添加到window對(duì)象:
原型 注意上述Person的定義方式,當(dāng)使用new來創(chuàng)建Person實(shí)例時(shí),將會(huì)執(zhí)行Person構(gòu)造函數(shù),也就是會(huì)聲明name屬性和Say方法,這樣可能產(chǎn)生效率問題,注意以下代碼:
比較p1和p2兩個(gè)Say函數(shù)指針,返回false,表示每個(gè)Person實(shí)例中的Say方法都是獨(dú)立的,而事實(shí)上Say函數(shù)的功能是完全一樣的,我們完全沒有必要為每個(gè)對(duì)象重新分配Say函數(shù)”對(duì)象“,如果Person實(shí)例很多,將會(huì)造成大量的內(nèi)存耗用。 如果將Say函數(shù)提取出來放入全局執(zhí)行范圍,似乎可解決次問題: 由于this始終和執(zhí)行上下文相關(guān),p1和p2實(shí)例中的Say方法中會(huì)正確地返回對(duì)應(yīng)實(shí)例的name屬性。但是,使用此方式有違面向?qū)ο蟮乃枷?,也失去了類型密封的原則。還會(huì)造成大量的全局函數(shù)。 為了解決這些缺點(diǎn),Javascript引出了原型的概念,簡(jiǎn)單理解,原型可以看成是類型的共享區(qū),原型本身是一個(gè)對(duì)象,而對(duì)象中的屬性對(duì)于類型來說是共享的。Javascript中每個(gè)類型通過prototype屬性來表示原型,通過這個(gè)屬性可指定共享方法:
為什么這里可以通過p1.Say來訪問Say方法呢?這是因?yàn)镋CMAScript標(biāo)準(zhǔn)規(guī)定了類型屬性的查找順序:先在類型的實(shí)例上查找,如果沒有則繼續(xù)在類型原型上查找,這一查找路徑采用短路算法,即找到首個(gè)后即返回,考慮如下代碼:
上面提到prototype實(shí)際上是一個(gè)對(duì)象,那么我們是否可以直接訪問呢? 在一些瀏覽器實(shí)現(xiàn)(如Chrome、Fixfox等)的確可通過實(shí)例的__proto__屬性來訪問內(nèi)部的prototype對(duì)象,這種特征表明Javascript引擎在每個(gè)對(duì)象的內(nèi)部都是通過一個(gè)變量來保存對(duì)prototype的引用,這保證了prototype對(duì)應(yīng)整個(gè)類型的實(shí)例來說是共享的,例如,你可在Chrome瀏覽器內(nèi)使用如下方式來訪問Say方法:
由于原型是一個(gè)對(duì)象,我們可以直接將一個(gè)對(duì)象賦值給prototype: 注意這個(gè)方式下,實(shí)際上是完全替換了Person的prototype,這與上面Person.prototype.name方式還是有細(xì)微差異的,這是因?yàn)槿魏晤愋?,Javascript引擎都會(huì)添加默認(rèn)的prototype,在這個(gè)prototype中包含一個(gè)對(duì)構(gòu)造函數(shù)的引用,即原型對(duì)象屬性constructor,所以通常使用替代prototype方式時(shí),我們需要手動(dòng)加上constructor屬性: 注意,由于prototype對(duì)于整個(gè)類型是共享的,那么在prototype中的引用類型可能會(huì)存在問題,前面的Say函數(shù)作為一個(gè)對(duì)象,也是引用類型,所以每個(gè)實(shí)例中的Say都指向原型對(duì)象中的同一個(gè)函數(shù),這本身沒有問題,也是我們使用原型的初衷,但對(duì)于其他引用對(duì)象,可能結(jié)果并不是我們想要的: p2.Say返回的是20,這是因?yàn)閛bj屬性作為原型屬性是共享的,在內(nèi)存中只存在一個(gè)實(shí)例,所以通過p1修改后,p2只能得到修改后的狀態(tài)。如果要避免此情況,可將obj屬性放到實(shí)例中:
|
|