一篇文章讓你搞懂JavaScript 原型和原型鏈
本文由葡萄城技術(shù)團(tuán)隊(duì)原創(chuàng)并首發(fā)
轉(zhuǎn)載請(qǐng)注明出處:葡萄城官網(wǎng)
與多數(shù)面向?qū)ο蟮拈_發(fā)語(yǔ)言有所不同,雖然JavaScript沒(méi)有引入類似類的概念(ES6已經(jīng)引入了class語(yǔ)法糖),但它仍然能夠大量的使用對(duì)象,那么如何將所有對(duì)象聯(lián)系起來(lái)就成了問(wèn)題。于是就有了本文中我們要講到的原型和原型鏈的概念。
原型和原型鏈作為深入學(xué)習(xí)JavaScript最重要的概念之一,如果掌握它了后,弄清楚例如:JavaScript的繼承,new關(guān)鍵字的原來(lái)、封裝及優(yōu)化等概念將變得不在話下,那么下面我們開始關(guān)于原型和原型鏈的介紹。
什么是原型?
JS中的對(duì)象包含了一個(gè)prototype的內(nèi)部屬性,這個(gè)屬性所對(duì)應(yīng)的就是該對(duì)象的原型。
我們先看下圖:a、b、c 分別為數(shù)組、對(duì)象、函數(shù)。
可以看到,三者都有一個(gè)屬性:__proto__
這個(gè) __proto__ 稱作 隱式原型。
除此之外,c還有一個(gè)屬性:prototype
這個(gè)prototype 稱作 顯式原型。
小結(jié)一下:
所有引用類型(函數(shù),數(shù)組,對(duì)象)都擁有__proto__屬性(隱式原型) 所有函數(shù)除了有_proto_屬性之外還擁有prototype屬性(顯式原型) 原型對(duì)象:每創(chuàng)建一個(gè)函數(shù),該函數(shù)會(huì)自動(dòng)帶有一個(gè)prototype屬性,該屬性是一個(gè)指針,指向了一個(gè)對(duì)象,我們稱之為原型對(duì)象。函數(shù)除了有_proto_屬性之外還擁有prototype屬性,我們借助構(gòu)造函數(shù)來(lái)尋找二者之間的關(guān)系。如下圖:
總結(jié)如下(結(jié)合上圖更容易理解):
1. 實(shí)例對(duì)象a只有__proto__(隱式原型),構(gòu)造函數(shù)既有 __proto__(隱式原型)也有prototype(顯式原型)
2. __proto__ 和 prototype 都是一個(gè)對(duì)象,既然是對(duì)象,就表示他們也有一個(gè) __proto__
a.__proto__.__proto__A.prototype.__proto__
3.實(shí)例對(duì)象a的隱式原型指向它構(gòu)造函數(shù)的顯式原型,指向的意思是恒等于
a.__proto__ === A.prototype
4. 當(dāng)調(diào)用某種方法或查找某種屬性時(shí),首先會(huì)在自身調(diào)用和查找,如果自身并沒(méi)有該屬性或方法,則會(huì)去它的__proto__屬性中調(diào)用查找,也就是它構(gòu)造函數(shù)的prototype中調(diào)用查找。
什么是原型鏈?
先看下圖,提出一個(gè)問(wèn)題:
1. 在 Object的顯式原型添加屬性b,為什么 示例對(duì)象p 能使用此屬性呢? p.b = b
2. 為什么 p.a 為undefined
如下圖所示
1. 實(shí)例對(duì)象p的隱式原型(__proto__)是一個(gè)對(duì)象,有兩個(gè)屬性值:constructor 和 __proto__
2. p.__proto__.constructor 返回的結(jié)果為構(gòu)造函數(shù)Person
3. p.__proto__.__proto__ .constructor 返回的結(jié)果為Object()函數(shù)
結(jié)合上面所講的顯式原型與隱式原型之間的關(guān)系,等同如下:
p.__proto__.__proto__ = Object.prototype
所以p.b打印結(jié)果為b,p沒(méi)有b屬性,會(huì)一直通過(guò)__proto__向上查找,最后當(dāng)查找到Object.prototype時(shí)找到,最后打印出b,向上查找過(guò)程中,得到的是Object.prototype,而不是Function.prototype,找不到a屬性,所以結(jié)果為undefined,這就是 原型鏈,通過(guò)__proto__向上進(jìn)行查找,最終到null結(jié)束。
總結(jié):
1. 查找屬性,如果本身沒(méi)有,則會(huì)去__proto__中查找,也就是構(gòu)造函數(shù)的顯式原型中查找,如果構(gòu)造函數(shù)的顯式原型中也沒(méi)有該屬性,因?yàn)闃?gòu)造函數(shù)的顯式原型也是對(duì)象,也有__proto__,那么會(huì)去它的顯式原型中查找,一直到null,如果沒(méi)有則返回undefined
2. p.__proto__.constructor == function Person(){}
3. p.___proto__.__proto__== Object.prototype
4. p.___proto__.__proto__.__proto__== Object.prototype.__proto__ == null
5. 通過(guò)__proto__形成原型鏈而非protrotype
什么是原型繼承?
Person.prototype 只是一個(gè)指針,指向的是原型對(duì)象,但是這個(gè)原型對(duì)象并不特別,它也只是一個(gè)普通對(duì)象。假設(shè)說(shuō),這時(shí)候,我們讓 Person.prototype 不再指向最初的原型對(duì)象,而是另一個(gè)類 (Animal)的實(shí)例,情況會(huì)怎樣呢?
執(zhí)行該代碼 Person.prototype = new Animal() 后,Person的prototype指針指向發(fā)生了變化,指向了一個(gè) Animal 實(shí)例。
當(dāng) p 去訪問(wèn) address 屬性時(shí),js會(huì)先在 p 的實(shí)例屬性中查找,發(fā)現(xiàn)找不到后,就會(huì)去 Person 的原型對(duì)象上 查找。因?yàn)镻erson的原型對(duì)象已經(jīng)被我們換成一個(gè)animal實(shí)例,所以就會(huì)先找animal實(shí)例的屬性,當(dāng)發(fā)現(xiàn)還是沒(méi)有 address屬性,就會(huì)去Animal的原型對(duì)象上查找,最終找到。
這就說(shuō)明,我們可以通過(guò)原型鏈的方式,實(shí)現(xiàn) Person 繼承 Animal 的所有屬性和方法。
結(jié)語(yǔ)
看到這,相信大家對(duì)原型和原型鏈的概念應(yīng)該已經(jīng)有了一定了解了,如果仍然不太理解,也不用氣餒,因?yàn)殚]包及原型鏈?zhǔn)荍avaScript最難理解的幾部分。相信之后在不斷的開發(fā)實(shí)踐中會(huì)使你理解的更為透徹,多學(xué)習(xí)多思考才能更快掌握。如果大家有任何反饋和問(wèn)題,也歡迎通過(guò)評(píng)論區(qū)告訴我,謝謝。
以上就是一篇文章讓你搞懂JavaScript 原型和原型鏈的詳細(xì)內(nèi)容,更多關(guān)于JavaScript 原型和原型鏈的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. 淺談SpringMVC jsp前臺(tái)獲取參數(shù)的方式 EL表達(dá)式2. jsp+servlet簡(jiǎn)單實(shí)現(xiàn)上傳文件功能(保存目錄改進(jìn))3. javascript xml xsl取值及數(shù)據(jù)修改第1/2頁(yè)4. XML入門的常見問(wèn)題(四)5. HTML5 Canvas繪制圖形從入門到精通6. XML入門的常見問(wèn)題(一)7. JavaWeb Servlet中url-pattern的使用8. 微信開發(fā) 網(wǎng)頁(yè)授權(quán)獲取用戶基本信息9. XML解析錯(cuò)誤:未組織好 的解決辦法10. asp批量添加修改刪除操作示例代碼
