一文詳解如何用原型鏈的方式實現JS繼承_第1頁
一文詳解如何用原型鏈的方式實現JS繼承_第2頁
一文詳解如何用原型鏈的方式實現JS繼承_第3頁
一文詳解如何用原型鏈的方式實現JS繼承_第4頁
一文詳解如何用原型鏈的方式實現JS繼承_第5頁
已閱讀5頁,還剩1頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第一文詳解如何用原型鏈的方式實現JS繼承目錄原型鏈是什么通過構造函數創建實例對象用原型鏈的方式實現繼承方法1:Object.create方法2:直接修改[[prototype]]方法3:使用父類的實例總結今天講一道經典的原型鏈面試題。

原型鏈是什么

JavaScript中,每當創建一個對象,都會給這個對象提供一個內置對象[[Prototype]]。這個對象就是原型對象,[[Prototype]]的層層嵌套就形成了原型鏈。

當我們訪問一個對象的屬性時,如果自身沒有,就會通過原型鏈向上追溯,找到第一個存在該屬性原型對象,取出對應值。

當然原型鏈不是無止境的,和單鏈表一樣,最后一個原型對象的值是null,原型鏈的所有對象都找不到指定的屬性時,我們會拿到undefined。

[[Prototype]]雖然無法通過腳本進行訪問,但大多數瀏覽器提供了__proto__屬性來訪問這個內置對象,但它并不是標準,無法兼容所有瀏覽器。

下面來舉幾個例子,讓讀者對原型鏈有一個直觀的認識:

通過對象字面量聲明a={}時,a的[[prototype]]就是Ototype。此時的原型鏈是:a-Ototype-null。這里有個易錯點,就是以為a的上一個原型對象是Object,其實并不對,Object其實只是一個構造函數。聲明數組arr=[1,2,4],它的原型鏈則是arr-Atotype-Ototype-null。Object.create(null)甚至能夠創建一個連[[prototype]]都沒有的真正的空對象,一般用于做字符串哈希表,比如vue源碼里就能經常看到。

通過構造函數創建實例對象

在JavaScript中,一個函數會在new關鍵字的配合下成為構造函數。也就是說,任何一個函數都可以成為構造函數。

當聲明一個構造函數時,它會有一個屬性名為prototype的對象(和[[prototype]]是不同的東西),這個對象就是原型對象。這個對象的constructor又反過來指向構造函數。

當我們對使用new關鍵字創建對象,被創建的對象的[[prototype]]會指向這個prototype。

functionRect(){}

constrect=newRect()

rect.__proto__===Rtotype//true

Rtotype.constructor===Rect//true

只要是通過newRect()創建的對象,無論多少次,它的[[prototype]]都是指向Rtotype。另外,Rtotype指向的是Ototype。

這樣,通過給構造函數的原型對象(Rtotype)添加一些方法(如Rtotype.draw),就能讓創建的多個實例對象共享同一個方法,減少內存的使用。

用原型鏈的方式實現繼承

理解了構造函數如何影響創建的實例的原型鏈后,我們來探討一下核心問題,如何使用原型鏈來實現繼承。

假設我們有一個Shape構造函數(父類)和Rect構造函數(子類)。代碼如下:

//父類

functionShape(){}

Stotype.draw=function(){

console.log('ShapeDraw')

Stotype.clear=function(){

console.log('ShapeClear')

//子類

functionRect(){}

實現繼承的代碼放這里

Rtotype.draw=function(){

console.log('RectDraw')

}

通過前面的學習,我們知道,正常情況下使用newRect創建的實例對象,它的原型鏈是這樣的:

rect-Rtotype-Otoype-null

現在我們要實現的繼承,其實就是在原型鏈中間再加一個原型對象Stotype。對此我們需要對Rtotype進行特殊的處理。

方法1:Object.create

Rtotype=Object.create(Stotype)

Rtotype.constructor=Rect//選用,如果要用到constructor

Rtotype.constructor=Rect//選用,如果要用到constructor

Object.create(proto)是個神奇的方法,它能夠創建一個空對象,并設置它的[[prototype]]為傳入的對象。

因為我們無法通過代碼的方式給[[prototype]]屬性賦值,所以使用了Object.create方法作為替代。

因為Rtotype指向了另一個新的對象,所以把constructor給丟失了,可以考慮把它放回來,如果你要用到的話。

缺點是替換掉了原來的對象。

方法2:直接修改[[prototype]]

如果就是不想使用新對象,只想修改原對象,可以使用廢棄的__proto__屬性,但不推薦。

不過另外還有一個方法Object.setPrototypeOf()可以修改對象的[[prototype]],但因為性能的問題,也不推薦使用。

Object.setPrototypeOf(Rtotype,Stotype)

//或

Rtotype.__proto__=Stotype

都不推薦使用,但確實能用。

方法3:使用父類的實例

Rtotype=newShape()

形成的原型鏈為:

rect-shape(替代掉原來的Rtotype)-Stotype-Ototype-null

基本能用,缺點是會產生副作用,就是執行newShap()可能會出現副作用,比如給創建的對象添加了一些屬性、發送了請求之類的,完全取決于構造函數內的代碼。

某種意義上,這個缺點是致命的。不推薦使用。

總結

用原型鏈的方式實現一個JS繼承,其實就是希望構造函數Son創建出來的對象son,它的原型鏈上加上父類Ptotype,所以最后就是要修改Stotype的[[prototype]]。

鑒于性能、兼容性、副作用等考慮,推薦使用方法1,即通過Object.create(Ptotype)創建一個指定了[[prototype]]的新對象,替換掉原來的Stotype指向的對象。

總結幾個核心知識點:

任何對象都有[[prototype]]屬性,讀寫對象屬性發現當前對象不存在時,會訪問[[prototype]]指向的對象嘗試訪問屬性,于是原型鏈形成了。函數創建時,它的prototype屬性會拿到一個原型對象。當函

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論