最近又很多同學(xué)在小猿圈學(xué)習(xí)群里討論原型和原型鏈的問題,看大家討論的熱火朝天担平,但是并沒有討論出很準(zhǔn)確的答案炬太,今天小猿圈就給大家分享一下如何理解原型和原型鏈
JavaScript的特點(diǎn)
JavaScript是一門直譯式腳本語言,是一種動(dòng)態(tài)類型考阱、基于原型的語言泌射。 JavaScript的靈活性不亞于C++粘姜,你可以使用JavaScript嘗試不同的程序設(shè)計(jì)范型。
比如類jQuery風(fēng)格的函數(shù)式編程熔酷、基于過程的指令式編程孤紧、以及基于原型的面向?qū)ο缶幊獭?/p>
不同于Java、C#等面向?qū)ο笳Z言纯陨,JavaScript采用基于原型的繼承方式坛芽。
為啥會(huì)有原型和原型鏈?
1994年翼抠,網(wǎng)景公司(Netscape)發(fā)布了Navigator瀏覽器0.9版咙轩,但是剛開始的Js沒有繼承機(jī)制,更別提像同時(shí)期興盛的C++和Java這樣擁有面向?qū)ο蟮母拍钜跤薄T趯?shí)際的開發(fā)過程中活喊,工程師們發(fā)現(xiàn)沒有繼承機(jī)制很難解決一些問題,必須有一種機(jī)制能將所有的對(duì)象關(guān)聯(lián)起來量愧。
Brendan Eich鑒于以上情況钾菊,但不想把Js設(shè)計(jì)得過為復(fù)雜帅矗,于是引入了new關(guān)鍵詞和constructor構(gòu)造函數(shù)來簡(jiǎn)化對(duì)象的設(shè)計(jì),引入了prototype函數(shù)對(duì)象來包含所有實(shí)例對(duì)象的構(gòu)造函數(shù)的屬性和方法煞烫,引入了proto和原型鏈的概念解決繼承的問題浑此。
原型模式
[if !supportLists]·???????[endif]每個(gè)函數(shù)都有一個(gè)prototype(原型)屬性
[if !supportLists]·???????[endif]這個(gè)屬性都有一個(gè)指針,指向一個(gè)對(duì)象
[if !supportLists]·???????[endif]這個(gè)對(duì)象包含由特定類型所有實(shí)例共享的屬性和方法
[if !supportLists]·???????[endif]使用原型的好處是 可以讓所有對(duì)象實(shí)例共享它包含的方法和屬性
通過in操作符和hasOwnProperty來判斷給定屬性是來自于原型還是實(shí)例
in- true 代表屬性在對(duì)象中存在 來自實(shí)例或者來自原型
hasOwnProperty- true代表屬性來自于實(shí)例 是實(shí)例屬性
原型鏈
ECMAScript中只支持實(shí)現(xiàn)繼承滞详,而且是通過原型鏈的方式來實(shí)現(xiàn)的凛俱。所以原型鏈?zhǔn)荍avaScript實(shí)現(xiàn)繼承的一種重要方式。
用戶定義類型的原型鏈
我們一般如何來檢查JavaScript的變量數(shù)據(jù)類型料饥?一般我們都是通過instanceof關(guān)鍵字蒲犬,可以基于原型鏈來檢測(cè)變量的類型。
我們可以先構(gòu)造一個(gè)原型鏈岸啡,再用instanceof來檢測(cè)類型:
[if !vml]
[endif]
[if !vml]
[endif]
由上面講的instanceof的結(jié)果原叮,可以判斷這些類型的繼承層級(jí):
[if !vml]
[endif]
事實(shí)上instanceof是通過原型鏈來檢測(cè)類型的,例如L
instanceof R: 如果R.prototype出現(xiàn)在了L的原型鏈上則返回true巡蘸,否則返回false奋隶。
用JavaScript來描述instanceof的實(shí)現(xiàn)邏輯是這樣的:
[if !vml]
[endif]
JavaScript原型鏈
先給大家看一個(gè)JavaScript的原型鏈結(jié)構(gòu)圖。
[if !vml]
[endif]
悄悄告訴你理解原型鏈的小技巧: 將__proto__箭頭視作泛化(子類到父類)關(guān)系赡若!
那么圖中所有的虛線將構(gòu)成一個(gè)繼承層級(jí)达布,而實(shí)線表示屬性引用团甲。
圖中給出了Object.prototype.__proto__ == null逾冬,但它還沒有標(biāo)準(zhǔn)化,在Chrome躺苦、Safari和Node.js下它是不同的東西身腻。
但可以看到JavaScript中所有對(duì)象的共同隱式原型為Object.prototype,它的上一級(jí)隱式原型是什么已經(jīng)不重要了匹厘,因?yàn)樗粫?huì)影響所有內(nèi)置對(duì)象以及用戶定義類型的原型鏈結(jié)構(gòu)嘀趟。
上圖其實(shí)已經(jīng)解釋了不同內(nèi)置對(duì)象instanceof的行為,我們來看Function和Object的特殊之處:
[if !supportLists]1.???[endif]Object是由Function創(chuàng)建的:因?yàn)镺bject.__proto__ === Funciton.prototype愈诚;
[if !supportLists]2.???[endif]同理她按,F(xiàn)unction.prototype是由Object創(chuàng)建的;
[if !supportLists]3.???[endif]Funciton是由Function自己創(chuàng)建的炕柔!
[if !supportLists]4.???[endif]Object.prototype是憑空出來的酌泰!
現(xiàn)在我們可以解釋特殊對(duì)象的instance行為了:
[if !vml]
[endif]
另外可以看到當(dāng)你聲明一個(gè)函數(shù)(比如Animal)時(shí),Animal.prototype會(huì)自動(dòng)被賦值為一個(gè)繼承自O(shè)bject的對(duì)象匕累, 而且該對(duì)象的constructor等于Animal。即:
[if !vml]
[endif]
值得注意的是Animal如果被Cat繼承欢嘿,Cat實(shí)例(比如cat)的constructor仍然是Animal衰琐。
[if !vml]
[endif]
總結(jié)
1.每個(gè)函數(shù)對(duì)象都有一個(gè) prototype 屬性也糊,這個(gè)屬性就是函數(shù)的原型對(duì)象。
2.原型鏈?zhǔn)荍avaScript實(shí)現(xiàn)繼承的重要方式羡宙,原型鏈的形成是真正是靠__proto__ 而非prototype狸剃。
不知道同學(xué)們有沒有明白呢?今天的分享就到這里了狗热,希望大家要收藏或者記到小本本上哦捕捂,吐過還有不懂得可以來小猿圈找我哦,小猿圈-IT自學(xué)人的小圈子斗搞。