JS中的原型和原型鏈詳解

JS中的原型和原型鏈是大家徹底搞懂JS面向對象及JS中繼承相關知識模塊非常重要的一個模塊疫衩,一旦突破這塊知識點壮莹,相信大家對JS會有一個更新翅帜、更全面的認識。

一命满、 什么是原型涝滴?

任何對象都有一個原型對象,這個原型對象由對象的內置屬性_proto_指向它的構造函數的prototype指向的對象胶台,即任何對象都是由一個構造函數創(chuàng)建的歼疮,但是不是每一個對象都有prototype,只有方法才有prototype诈唬。

二韩脏、 為什么要使用原型

試想如果我們要通過Foo()來創(chuàng)建很多很多個對象,如果我們是這樣子寫的話铸磅。

那么我們創(chuàng)建出來的每一個對象赡矢,里面都有showName和showAge方法,這樣就會占用很多的資源愚屁。

而通過原型來實現的話济竹,只需要在構造函數里面給屬性賦值痕檬,而把方法寫在Foo.prototype屬性(這個屬性是唯一的)里面霎槐。這樣每個對象都可以使用prototype屬性里面的showName、showAge方法梦谜,并且節(jié)省了不少的資源丘跌。如下圖所示:

要想徹底了解原型,我們必須從對象的創(chuàng)建過程開始唁桩。就像你要徹底了解一個人闭树,要從他的原生家庭,從他的出生環(huán)境了解起荒澡。有些基因是從出生就開始植入到對象內的报辱。所以,我們首先來看對象的創(chuàng)建過程单山。

三碍现、 創(chuàng)建對象的過程

1. 聲明方法的過程

首先幅疼,當我們聲明一個function關鍵字的方法時,會為這個方法添加一個prototype屬性昼接,指向默認的原型對象爽篷,并且此prototype的constructor屬性也指向方法對象。此二個屬性會在創(chuàng)建對象時被對象的屬性引用慢睡。

2. 通過構造函數創(chuàng)建對象

實踐證明逐工,new出來的對象,它的constructor指向了方法對象漂辐,它的_proto_和prototype相等泪喊。即new一個對象,它的_proto_屬性指向了方法的prototype屬性髓涯,并且constructor指向了prototype的constructor屬性坦冠。

為什么會導致上述結果?這涉及到對象創(chuàng)建的過程虑鼎,一旦明白對象創(chuàng)建的過程這個問題就迎刃而解了谋右。下面我們來看

3. 創(chuàng)建一個對象的過程

JS中創(chuàng)建對象的常見方法有三種:①通過字面量創(chuàng)建對象;②通過構造函數創(chuàng)建對象育八;③通過Object.create方法創(chuàng)建對象对途。

方式一:通過字面量創(chuàng)建對象

這種形式就是對象字面量,通過對象字面量構造出的對象髓棋,其__proto__指向Object.prototype实檀。

所以,其實Object是一個函數也不難理解了按声。Object膳犹、Function都是是JS自帶的函數對象。我們可以通過下面的代碼驗證:

方式二:通過構造函數創(chuàng)建對象

new一個構造函數签则,相當于實例化一個對象须床,這期間其實進行了這三個步驟:

【1】創(chuàng)建對象,設為f渐裂,即: var? f = {};

【2】上文提到了豺旬,每個對象都有__proto__屬性,該屬性指向一個對象柒凉,這里族阅,將f對象的__Proto__指向構造函數Foo的原型對象(Foo.prototype);

【3】將f作為this去調用構造函數Foo,從而設置f的屬性和方法并初始化膝捞。

當這3步完成坦刀,這個f對象就與構造函數Foo再無聯(lián)系,這個時候即使構造函數Foo再加任何成員,都不再影響已經實例化的f對象了鲤遥。

此時央渣,f對象具有了name和age屬性,同時具有了構造函數Foo的原型對象的所有成員渴频,當然芽丹,此時該原型對象是沒有成員的。

上述過程可以用下列代碼表述:

簡單的總結下就是:

【1】js在創(chuàng)建對象的時候卜朗,都有一個叫做__proto__的內置屬性拔第,用于指向創(chuàng)建它的函數對象的原型對象prototype;

【2】那么一個對象的__proto__屬性究竟怎么決定呢场钉?答案顯而易見了:是由構造該對象的方法決定的蚊俺。

方式三:通過Object.create方法創(chuàng)建對象

這種情況下,person2的__proto__指向person1逛万。在沒有Object.create函數的時候泳猬,人們大多是這樣做的:

4. 延伸

從上面說明的過程中,我們發(fā)現只要是對象是由構造函數來創(chuàng)建的宇植,并且內部二個屬性是從構造函數的prototype衍生的一個指向得封,而構造函數的prototype也是一個對象,那么它應該肯定也有一個構造函數指郁,首先它是一個Object {} 對象忙上,那么它的構造函數肯定是Object,所以就會有一個指針_proto_指向Object.prototype。最后Object.prototype因為沒有_proto_闲坎,指向null疫粥,這樣就構成了一個原型鏈。

四腰懂、 原型鏈

1.? 什么是原型鏈梗逮?

原型鏈的核心就是依賴對象的_proto_的指向,當自身不存在的屬性時绣溜,就一層層的扒出創(chuàng)建對象的構造函數慷彤,直至到Object時,就沒有_proto_指向了涮毫。

也就是說瞬欧,當試圖得到一個對象的屬性時贷屎,如果這個對象本身不存在這個屬性罢防,那么就會去它構造函數的’prototype’屬性中去尋找。那又因為’prototype’屬性是一個對象唉侄,所以它也有一個’_ _ proto_ _'屬性咒吐。

上述代碼運行結果,直觀地用下圖表示,更便于大家理解:

首先恬叹,fn的構造函數是Foo()候生。所以:fn._ _ proto _ _ ===? Foo.prototype

又因為Foo.prototype是一個普通的對象,它的構造函數是Object绽昼,所以:

Foo.prototype._ _ proto _ _ ===? Object.prototype

通過上面的代碼唯鸭,我們知道這個toString()方法是在Object.prototype里面的,當調用這個對象的本身并不存在的方法時硅确,它會一層一層地往上去找目溉,一直到null為止。

所以當fn調用toString()時菱农,JS發(fā)現fn中沒有這個方法缭付,于是它就去Foo.prototype中去找,發(fā)現還是沒有這個方法循未,然后就去Object.prototype中去找陷猫,找到了,就調用Object.prototype中的toString()方法的妖。

這就是原型鏈绣檬,fn能夠調用Object.prototype中的方法正是因為存在原型鏈的機制。

另外嫂粟,在使用原型的時候河咽,一般推薦將需要擴展的方法寫在構造函數的prototype屬性中,避免寫在_ _ proto _ _屬性里面赋元。(上述為什么使用原型有解釋原因)

5.? 如何分析原型鏈?

因為_proto_實質找的是prototype忘蟹,所以我們只要找這個鏈條上的構造函數的prototype。其中Object.prototype是沒有_proto_屬性的搁凸,它==null媚值。

屬性搜索原則:

【1】當訪問一個對象的成員的時候,會現在自身找有沒有护糖,如果找到直接使用褥芒。

【2】如果沒有找到,則去原型鏈指向的對象的構造函數的prototype中找嫡良,找到直接使用锰扶,沒找到就返回undifined或報錯。

始終牢記:JS在創(chuàng)建對象的時候寝受,都有一個叫做__proto__的內置屬性坷牛,用于指向創(chuàng)建它的函數對象的原型對象prototype。

而原型鏈的基本思想就是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法很澄。

五京闰、 總結

1颜及、所有的引用類型(數組、函數蹂楣、對象)可以自由擴展屬性(除null以外)俏站。

2、所有的引用類型都有一個’_ _ proto_ _'屬性(也叫隱式原型痊土,它是一個普通的對象)肄扎。

3、所有的函數都有一個’prototype’屬性(這也叫顯式原型赁酝,它也是一個普通的對象)反浓。

4、所有引用類型赞哗,它的’_ _ proto_ _'屬性指向它的構造函數的’prototype’屬性雷则。

5、當試圖得到一個對象的屬性時肪笋,如果這個對象本身不存在這個屬性月劈,那么就會去它的’_ _ proto_ _'屬性(也就是它的構造函數的’prototype’屬性)中去尋找。

給大家推薦個cocos學習交流群 點擊鏈接即可加群??加群鏈接

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末藤乙,一起剝皮案震驚了整個濱河市猜揪,隨后出現的幾起案子,更是在濱河造成了極大的恐慌坛梁,老刑警劉巖而姐,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異划咐,居然都是意外死亡拴念,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門褐缠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來政鼠,“玉大人,你說我怎么就攤上這事队魏」悖” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵胡桨,是天一觀的道長官帘。 經常有香客問我,道長昧谊,這世上最難降的妖魔是什么刽虹? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮揽浙,結果婚禮上状婶,老公的妹妹穿的比我還像新娘意敛。我一直安慰自己馅巷,他們只是感情好膛虫,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钓猬,像睡著了一般稍刀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敞曹,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天账月,我揣著相機與錄音,去河邊找鬼澳迫。 笑死局齿,一個胖子當著我的面吹牛,可吹牛的內容都是我干的橄登。 我是一名探鬼主播抓歼,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拢锹!你這毒婦竟也來了谣妻?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤卒稳,失蹤者是張志新(化名)和其女友劉穎蹋半,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體充坑,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡减江,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了捻爷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片您市。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖役衡,靈堂內的尸體忽然破棺而出茵休,到底是詐尸還是另有隱情,我是刑警寧澤手蝎,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布榕莺,位于F島的核電站,受9級特大地震影響棵介,放射性物質發(fā)生泄漏钉鸯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一邮辽、第九天 我趴在偏房一處隱蔽的房頂上張望唠雕。 院中可真熱鬧贸营,春花似錦、人聲如沸岩睁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捕儒。三九已至冰啃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刘莹,已是汗流浹背阎毅。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留点弯,地道東北人扇调。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像抢肛,于是被迫代替她去往敵國和親狼钮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容