繼承是我們在實作物件導向程式設計的時候很重要的一個手段。雖然我們講不能過度繼承,多利用組合代替繼承,但是繼承總是免不了的。這裡要討論的就是Javascript中的繼承機制。
Javascript中實際上是沒有繼承的概念的,但是我們可以透過一些手段來模仿實現它。這種繼承實際上把一個物件複製到另外一個物件內部。你要注意的是所有的本地類別和宿主類別是不能作為基底類別被繼承的,主要是為了安全方面的考慮。
Javascript中的繼承大約有三類:1.物件冒充;2.原型繼承;3.二者的混合。
一、物件冒充
其實物件冒充是跟this關鍵字緊密連結在一起的(所以說充分理解Javascript中的this關鍵字是多麼的重要:P)。建構函數使用this來給屬性和方法賦值,而建構函數也可以看作為一個普通的函數,所以我們就可以使我們的基底類別的建構函數成為子類別的建構函數,然後在子類別的內部呼叫這個函數,那麼子類別就會得到父類別的屬性和方法。
原理很簡單,那我們要怎麼實現呢?下面就以程式碼範例,實際的操作一下。
物件冒充實作方法一,我們最常用的新物件的方法:
為了驗證以上的方法是否正確,你可以親自測試下,我將測試用的程式碼寫在下面:
這就是所謂的物件冒充了,另外物件冒充還有另外兩種實現的方式,雖然它們的實作手段不一樣,但是它們的原理是一樣的。
物件冒充實作方法二,使用call方法:
透過程式碼也能看出來,第一種方法中我們新建了函數指標指向父類,呼叫函數,然後將指標刪除。而這裡我們之間用call方法在this物件下面運行父類別的建構函數,實現了同樣的目的。另外與call方法相對於的則就是apply方法啦。
物件冒充實作方法三,使用apply方法:
其實大家可以看到,apply方法跟call方法是非常類似的,只不過傳遞參數是略有不同罷了。
二、原型繼承
大家應該對prototype物件有所了解,原型物件上的所有屬性和方法都會傳遞給類別的所有實例,所有當我們把父類別的所有屬性和方法付給子類別的prototype物件時也就相當於實現了我們的繼承。
子類別想要取得父類別的所有屬性和方法,那我們將父類別的一個實例直接付給子類別的prototype對象,那我們的子類別不就相當於取得了父類別的所有物件和方法?
程式碼範例伺候:
注意這裡的父類別的建構子需要確保沒有參數。因為即使有建構參數在實現原型繼承的時候你也無法傳遞=.=!
三、混合繼承
顧名思義,混合繼承就是前兩種方式的混合使用了。
使用物件冒充實作了向父類別傳遞參數,同時使用原型繼承實現了對公有方法的繼承。
說完這三繼承方式了,下面該說到問題的時候了。
你可能會不解,為什麼有了物件冒充,有了原型繼承還要再弄出個什麼混合繼承,對,最重要的也就是這個問題。
1.如果你實際測試一下,你會發現透過物件冒充的方式實現的繼承,子類別是無法存取到父類別的原型鏈上的方法的。
2.而用原型繼承,則會把所有的屬性變成共享的屬性,如果你同一個子類別實作兩個實例,你會發現你的所有實例共享所有的屬性。
3.但這肯定是不合適的了。所以就有了混合繼承的方式,讓屬性繼續保持私有,同時讓子類別能夠存取父類別的原型鏈的方法。
你可以親自動手試一下,在物件冒充繼承的時候,子類別無法存取父類別的原型鏈方法,原型鏈繼承子類別的所有實例共用所有父類別屬性。這裡我就不寫例子了。