JavaScript原型和原型鏈詳解
基于原型編程
在面向?qū)ο蟮木幊陶Z言中,類和對象的關(guān)系是鑄模和鑄件的關(guān)系,對象總是從類創(chuàng)建而來,比如Java中,必須先創(chuàng)建類再基于類實(shí)例化對象。
而在基于原型編程的思想中,類并不是必須的,對象都是通過克隆另外一個(gè)對象而來,這個(gè)被克隆的對象就是原型對象。
基于原型編程的語言通常遵循下面的規(guī)則:
- 所有的數(shù)據(jù)都是對象
- 要得到一個(gè)對象,不是通過實(shí)例化類,而是找到一個(gè)對象作為原型并克隆它
- 無法自己直接創(chuàng)建一個(gè)對象,對象都是克隆產(chǎn)生,必須有一個(gè)根對象,然后克隆它才可以創(chuàng)建對象
- 對象會(huì)記住它的原型
- 如果對象無法響應(yīng)某個(gè)請求,它會(huì)把這個(gè)請求委托給自己的原型
函數(shù)和對象
JavaScript是基于原型的語言,但JavaScript并非嚴(yán)格遵循原型編程的第一條規(guī)則,其中基本類型undefined、number、string、boolean就不是對象,其模仿Java,分為了基本類型和對象類型,當(dāng)然和Java一樣,基本類型可以使用包裝的形式變?yōu)閷ο蟆?br />這里先探討一個(gè)問題,有助于后面理解原型和原型鏈,那就是“所有的數(shù)據(jù)都是對象,函數(shù)也是對象“,雖然函數(shù)是對象,但是函數(shù)擁有很多普通對象不具備的特性:
- 可執(zhí)行性:函數(shù)可以被調(diào)用執(zhí)行
- 閉包:函數(shù)可以創(chuàng)建閉包
- 構(gòu)造函數(shù):函數(shù)可以作為構(gòu)造函數(shù),去創(chuàng)建對象實(shí)例,理論上,除了
Object.create創(chuàng)建的對象,都是通過構(gòu)造函數(shù)創(chuàng)建的對象。 - 原型對象屬性:除了箭頭函數(shù),每個(gè)函數(shù)都有一個(gè)
prototype屬性,它是一個(gè)對象,用于存儲(chǔ)通過該構(gòu)造函數(shù)創(chuàng)建的所有實(shí)例的共享屬性和方法。
JavaScript原型
從上面可以得知,函數(shù)都有 prototype 屬性,稱之為原型,也稱為原型對象,原型對象里面可以存放屬性和方法,共享給實(shí)例對象使用,用于實(shí)現(xiàn)繼承效果。
這里的函數(shù)指的是構(gòu)造函數(shù),即可以通過new創(chuàng)建對象的函數(shù),在JavaScript中普通函數(shù)都可以是構(gòu)造函數(shù),除了箭頭函數(shù)。
箭頭函數(shù)沒有
prototype屬性是為了保持它們的設(shè)計(jì)簡潔性,避免與原型鏈相關(guān)的復(fù)雜性和潛在問題。箭頭函數(shù)同時(shí)不能使用new實(shí)例化對象。如果你需要定義一個(gè)構(gòu)造器函數(shù),應(yīng)該使用普通函數(shù)而不是箭頭函數(shù)。
舉例說明:
const arr = new Array(1, 2, 3) arr.reverse() arr.sort()
在上面的代碼中 Array 就是一個(gè)構(gòu)造函數(shù),reverse和sort都是 Array.prototype 原型對象上的函數(shù)。
這里有個(gè)問題,為何要將這些方法放在 prototype 原型屬性上,而不是放在構(gòu)造函數(shù)內(nèi)部呢?
我們來看下面的代碼:
function Person() {
this.getName = function () {
console.log('person')
}
}
Person.prototype.getProtoName = function () {
console.log('proto person')
}
const person = new Person()
const person1 = new Person()
console.log(person.getName === person1.getName) // false
console.log(person.getProtoName === person1.getProtoName) // true很明顯,雖然在實(shí)例化對象上都可以調(diào)用這些方法,但兩者有本質(zhì)的不同,將方法放在 prototype 原型對象上,之后實(shí)例化的對象使用的都是同一個(gè)方法,類似于Java的類方法,而構(gòu)造函數(shù)內(nèi)的方法,則會(huì)重新創(chuàng)建,也就是實(shí)例對象方法。
JavaScript原型鏈
了解完原型之后,再來看原型鏈就非常簡單了。
- 對象可以調(diào)用其構(gòu)造函數(shù)的
prototype原型對象的屬性和方法 - 原型對象也是對象,同樣也可以調(diào)用其構(gòu)造函數(shù)的prototype原型對象的屬性和方法
- 一層一層的形成一條鏈路就是原型鏈
如圖所示:
解讀:
- 在瀏覽器中,通常使用對象的
__proto__即可找到對象的原型對象,每個(gè)對象都有__proto__屬性(還是要去除Object.create創(chuàng)建的),用于指向它的原型對象。 - 前面基于原型編程有一個(gè)規(guī)則是,必須有一個(gè)根對象,JavaScript中根對象是:
Object.prototype,其是一個(gè)空對象。
原型鏈經(jīng)典圖片
最后結(jié)合上面的內(nèi)容,來看看下面的經(jīng)典原型鏈圖:
從上圖可以看出左邊是實(shí)例對象,中間是構(gòu)造函數(shù),右邊是原型對象,圖中還包含了一些其它內(nèi)容:
函數(shù)是一個(gè)函數(shù),同時(shí)也是一個(gè)對象:
構(gòu)造函數(shù)作為一個(gè)函數(shù)時(shí),擁有原型對象屬性 prototype同時(shí)函數(shù)也是一個(gè)對象,函數(shù)都是由構(gòu)造函數(shù) Function 構(gòu)造出來的,包括 Function 函數(shù)本身,可以看上圖中 function Foo()、function Object()、function Function() 的 __proto__ 都是指向 Funtion.prototype,這是函數(shù)比較特殊的一點(diǎn)。
這個(gè)地方有點(diǎn)繞,再理一下,函數(shù)的 prototype 屬性是這個(gè)函數(shù)自己的屬性,而函數(shù)的 __proto__ 指向的是其構(gòu)造函數(shù)的原型對象,可以理解為父級(jí)的屬性,兩者是不同的。
總結(jié)
- JavaScript是基于原型編程,創(chuàng)建對象是通過克隆對象的形式,不是通過類創(chuàng)建。
- 函數(shù)都擁有
prototype原型屬性,實(shí)例化對象的__proto__屬性指向這個(gè)原型屬性,對象可以直接調(diào)用原型對象的方法和屬性,不用寫__proto__再調(diào)用,兩者效果一致。 - 對象的
__proto__指向構(gòu)造函數(shù)的prototype,構(gòu)造函數(shù)的prototype同樣是對象,其__proto__指向上一層原型對象,直到Object.prototype,形成原型鏈。
到此這篇關(guān)于JavaScript原型和原型鏈的文章就介紹到這了,更多相關(guān)JavaScript原型和原型鏈內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js實(shí)現(xiàn)前端跨域postMessage的具體使用
這篇文章主要介紹了js實(shí)現(xiàn)前端跨域postMessage的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
微信公眾號(hào)開發(fā)之微信支付代碼記錄的實(shí)現(xiàn)
這篇文章主要介紹了微信公眾號(hào)開發(fā)之微信支付代碼記錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
JavaScript實(shí)現(xiàn)找質(zhì)數(shù)代碼分享
這篇文章主要介紹了JavaScript實(shí)現(xiàn)找質(zhì)數(shù)代碼分享,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-03-03
javascript設(shè)計(jì)模式之單體模式學(xué)習(xí)筆記
這篇文章主要為大家詳細(xì)介紹了javascript設(shè)計(jì)模式之單體模式學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
Openlayers+EasyUI Tree動(dòng)態(tài)實(shí)現(xiàn)圖層控制
這篇文章主要為大家詳細(xì)介紹了Openlayers+EasyUI Tree動(dòng)態(tài)實(shí)現(xiàn)圖層控制,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
微信小程序 this.triggerEvent()的具體使用
這篇文章主要介紹了微信小程序 this.triggerEvent()的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
javascript FAQ函數(shù)(提問+回復(fù))
javascript FAQ函數(shù),當(dāng)點(diǎn)擊問題時(shí)顯示下面的回復(fù)內(nèi)容。2009-07-07

