2020-01-03:繼承原理(原型鏈)

2.4組合使用構(gòu)造函數(shù)模式和原型模式

綜合使用構(gòu)造函數(shù)和原型模式可以避免之前二者的問題谨履,而取其長處俱箱。

通常來說陡厘,我們使用構(gòu)造函數(shù)模式定義實(shí)例屬性,而原型模式定義公用的方法和屬性扶歪。這樣做之后理肺,每個(gè)實(shí)例都會有一份只屬于自己的屬性副本,同時(shí)又可以調(diào)用共有方法:

同時(shí)使用構(gòu)造函數(shù)法和原型模式

在這里善镰,我們需要的實(shí)例屬性都是在構(gòu)造函數(shù)中定義的妹萨,而實(shí)例共享的屬性和方法則是在原型中定義的。

2.5動態(tài)原型模式

js的原型模式和其他OO語言最大的不同就是構(gòu)造函數(shù)和原型分別獨(dú)立炫欺,這就是動態(tài)原型模式致力于解決的方案乎完。動態(tài)原型模式將所有信息封裝在構(gòu)造函數(shù)中,通過構(gòu)造函數(shù)在必要情況下初始化原型:

只有在sayName方法不存在的情況下品洛,才會動態(tài)寫入原型中树姨。

在動態(tài)原型模式中,通常會使用instanceof和typeof進(jìn)行類型檢測桥状。并且需要注意帽揪,在使用動態(tài)原型模式時(shí),不能使用對象字面量重寫原型岛宦,原因請參照2020-01-02中有關(guān)重寫原型時(shí)可能會切斷既有實(shí)例和原型之間的聯(lián)系台丛。

2.6寄生構(gòu)造函數(shù)模式

這種使用方式通常用來創(chuàng)建一個(gè)基于既有對象耍缴,而又比既有對象多一些額外方法或?qū)傩缘膶ο罄巍Ee個(gè)例子,我們需要建設(shè)一個(gè)具有額外方法的特殊數(shù)組防嗡,那么就可以使用寄生構(gòu)造函數(shù)模式变汪。

寄生構(gòu)造函數(shù)模式的思想與工廠模式幾乎相同:在構(gòu)造函數(shù)內(nèi)new一個(gè)既有對象,通過對這個(gè)既有對象的實(shí)例增加新的屬性或方法蚁趁,達(dá)到不修改既有對象的構(gòu)造函數(shù)便可以添加新的方法裙盾。

舉個(gè)例子,假如我們需要一個(gè)具有額外方法的特殊數(shù)組:

Array是既有對象,通過在構(gòu)造函數(shù)內(nèi)為數(shù)組實(shí)例values添加方法實(shí)現(xiàn)不修改Array的構(gòu)造函數(shù)就可以為這個(gè)新實(shí)例添加新的方法番官。

2.7穩(wěn)妥構(gòu)造函數(shù)模式

穩(wěn)妥對象庐完,指的是沒有公共屬性,其方法也不引用this對象徘熔。通常會被使用在一些安全的和環(huán)境中门躯。定義在其中的屬性通常只能用添加的方法訪問(類似私有屬性的概念)

看一個(gè)例子:

除了調(diào)用sayName方法外,沒有其他任何方式可以訪問數(shù)據(jù)成員

3.繼承

一般的OO語言繼承有兩種方式:接口繼承和實(shí)現(xiàn)繼承酷师。接口繼承只繼承方法簽名讶凉,而實(shí)際繼承則繼承實(shí)際方法。但是因?yàn)樵趈s中函數(shù)沒有簽名山孔,因此js只支持實(shí)現(xiàn)繼承懂讯。繼承的主要原理是依賴原型鏈實(shí)現(xiàn)。

3.1原型鏈

原型鏈?zhǔn)菍?shí)現(xiàn)js中繼承的主要方法台颠。其基本四項(xiàng)是利用原型讓一個(gè)引用類型繼承另外一個(gè)引用類型的屬性和方法褐望。

首先簡單回顧以下構(gòu)造函數(shù),原型對象串前,和實(shí)例之間的關(guān)系:

一個(gè)構(gòu)造函數(shù)有一個(gè)原型對象譬挚,構(gòu)造函數(shù)可以通過prototype訪問原型對象;

一個(gè)原型對象包括一個(gè)指向構(gòu)造函數(shù)的指針constructor酪呻;

實(shí)例包含一個(gè)指向原型對象的指針减宣;

假如我們讓原型對象A等于原型對象B的實(shí)例b,則原型對象A同時(shí)也是原型對象B的實(shí)例b玩荠,因此其內(nèi)就會包括一個(gè)指向原型對象B的指針漆腌。相應(yīng)的,如果原型對象B等于原型對象C的實(shí)例c阶冈,則原型對象B同時(shí)也是原型對象C的實(shí)例c闷尿,因此其內(nèi)部就會包括一個(gè)指向原型對象C的指針女坑。這樣層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條匆骗。

下面我們看一個(gè)實(shí)現(xiàn):

可以看到,child繼承了father

在這個(gè)例子中我們定義了兩個(gè)類型father和child碉就,child繼承了father的方法和屬性。繼承的過程是通過將child的原型對象重寫為Father的實(shí)例完成的瓮钥。本質(zhì)是重寫原型對象筋量,以一個(gè)新類型的實(shí)例代替。

此時(shí)我們也可以在child中再添加其他方法:

只需在child的原型中添加方法即可

通過一張關(guān)系圖可以明晰child和father之間的關(guān)系:

instance是SubType.prototype的實(shí)例肋拔,SubType.prototype是SuperType.prototype的實(shí)例

這其中的SubType.prototype既是instance實(shí)例的原型,又是SuperType.prototype的實(shí)例呀酸。因此他擁有一個(gè)實(shí)例才擁有的[[prototype]]的指針,這個(gè)指針指向它的原型(SuperType.prototype),同時(shí)它的實(shí)例instance的[[prototype]]則指向它七咧。

此時(shí)如果調(diào)用instance.subproperty屬性,則調(diào)用了一層搜索(搜索實(shí)例)艾栋。

如果調(diào)用instance.getSubValue()方法,實(shí)際上是我們之前介紹過的二層搜索(搜索實(shí)例的原型)蝗砾。

而調(diào)用instance.getSuperValue()方法,實(shí)際上是第三層搜索(搜索實(shí)例的原型悼粮,而將實(shí)例的原型作為實(shí)例2闲勺,搜索實(shí)例2的原型)扣猫。

因此通過實(shí)現(xiàn)原型鏈菜循,本質(zhì)上是擴(kuò)展了前面我們介紹的原型搜索機(jī)制


1.1別忘記默認(rèn)的原型

實(shí)際上在上面的原型鏈中還少了一環(huán)申尤,我們知道所有引用類型都默認(rèn)繼承了Object癌幕,這個(gè)繼承也是通過原型鏈實(shí)現(xiàn)的,因此對于SuperType.Prototype,它實(shí)際上也是Object的一個(gè)實(shí)例昧穿。它的[[Prototype]]實(shí)際上指向了Object.prototype:

這里展示一個(gè)完整的原型鏈

這也正是所有自定義類型都會繼承toString,valueOf,isPrototypeOf這些方法的根本原因勺远,實(shí)際上,我們在訪問instance.toString()時(shí)时鸵,本質(zhì)上都是通過4次搜索后胶逢,調(diào)用了Object.prototype中的方法。

我們可以看到饰潜,只有底層的SubType.Prototype沒有constructor指向其構(gòu)造函數(shù)初坠,這是因?yàn)镾ubType.Prototype是我們?nèi)斯ぶ貙戇^的,因此它的constructor不指向其構(gòu)造函數(shù)囊拜。

我們可以看到某筐,子類的constructor指向了父類的構(gòu)造函數(shù)

2.確定原型和實(shí)例的關(guān)系

子類繼承父類后,如果使用instanceof測試針對Object冠跷,F(xiàn)ather南誊,child三個(gè)類型,都會返回true蜜托。

三個(gè)構(gòu)造函數(shù)都是instance的構(gòu)造函數(shù)

同樣同一個(gè)屬性isPrototypeOf()方法抄囚,只要時(shí)原型鏈中出現(xiàn)的原型,都時(shí)該原型鏈所派生的實(shí)例的原型橄务。如果使用isPrototypeOf()測試針對Object幔托,F(xiàn)ather,child三個(gè)類型蜂挪,都會返回true重挑。

三個(gè)原型都是instance的原型

3.謹(jǐn)慎定義方法

在這里只要強(qiáng)調(diào)無論如何,給原型添加方法的代碼一定要放在替換原型的語句之后棠涮。換個(gè)更淺顯的說法:給子類加方法一定要在重寫子類之后谬哀。

重寫方法和添加新方法

重寫父類方法的本質(zhì)其實(shí)是在二層搜索時(shí)就找到了getValue(),因此解釋器也就不會再進(jìn)行三層搜索严肪,去Father.prototype中找getValue()方法了史煎。

同樣,需要注意的是篇梭,在給子類添加屬性或方法的時(shí)候,不能使用字面量法添加新屬性和方法恬偷。因?yàn)槲覀冎溃置媪糠ū举|(zhì)上也是在重寫原型對象喉磁。這會導(dǎo)致[[prototype]]指針失靈官脓。

4.原型鏈的問題

原型鏈的問題之一與之前一樣,都來自于包含引用類型值的原型卑笨。我們知道,原型中引用類型的屬性會被所有實(shí)例共享妖滔。這會導(dǎo)致在通過原型來實(shí)現(xiàn)繼承時(shí)桶良,原型實(shí)際上會變成另外一個(gè)類型的實(shí)例,原先的實(shí)例屬性(this.colors)也就順理成章地變成了現(xiàn)在的原型屬性(Subtype.prototype.colors)了陨帆。

和原型的問題一樣,都是通過原型繼承的引用屬性會引起共享

因?yàn)镾ubType通過原型鏈繼承了SuperType后承二,SubType.propotype就變成了SuperType的實(shí)例,因此它也擁有了colors屬性亥鸠。這和專門創(chuàng)建了一個(gè)SubType.prototype.colors屬性是一個(gè)道理。因此所有它的實(shí)現(xiàn)就會共享這個(gè)colors屬性神妹,這本質(zhì)上和原型的問題是一致的家妆。

原型的問題之二是在創(chuàng)建字類型的實(shí)例時(shí),無法向父類型的構(gòu)造函數(shù)中傳遞參數(shù)揩徊,類似java中super的用法。如果強(qiáng)行這樣做塑荒,則很有可能印象已經(jīng)實(shí)現(xiàn)的實(shí)例。

基于這兩個(gè)問題彼硫,我們在實(shí)踐中通常很少會單獨(dú)使用原型鏈凌箕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市牵舱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌礁凡,老刑警劉巖慧妄,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異窟蓝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)运挫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滑臊,“玉大人箍铲,你說我怎么就攤上這事」鼗” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵贮折,是天一觀的道長资盅。 經(jīng)常有香客問我,道長每庆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任缤灵,我火速辦了婚禮蓝晒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芝薇。我一直安慰自己,他們只是感情好馋劈,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布灭红。 她就那樣靜靜地躺著,像睡著了一般变擒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上策添,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機(jī)與錄音唯竹,去河邊找鬼。 笑死浸颓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的产上。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼仪媒,長吁一口氣:“原來是場噩夢啊……” “哼谢鹊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起佃扼,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎艘狭,沒想到半個(gè)月后翠订,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡官撼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年似谁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巩踏。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖菠净,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情毅往,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布洁桌,位于F島的核電站,受9級特大地震影響另凌,放射性物質(zhì)發(fā)生泄漏残拐。R本人自食惡果不足惜碟嘴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娜扇。 院中可真熱鬧,春花似錦雀瓢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽把沼。三九已至,卻和暖如春饮睬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捆愁。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工窟却, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人夸赫。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像胁附,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子控妻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容