我們日常開發(fā)都會用到ES6, 比如我們擼React,寫組件肯定擼過class XX extends React.Component. constructor(){super(xx)}之類的。
今天就來看看這個class,我們知道JS里本身是沒有class這個概念,其他語言比如java,python是天生就有class的,JS肯定不服啊,所以在ES6里就引入了class,那么是class就真的是class嗎?No,此class非彼class,用的babel的同學肯定會知道,當我們打開編譯后的es6代碼,實際就是es5,里面并沒有class,還是prototype什么那些一堆亂七八糟的玩意兒,說白了,class只是一個語法糖,方便我們開發(fā)寫代碼而已。
好,那我們就來看看什么是真正的繼承吧。
Type 1: 原型鏈的方式可以實現(xiàn),talk is cheap, show me the code.亮代碼
function Taylor () {
this.name = 'Taylor'
this.price = 7777
}
function Guitar () {
this.dalao= '雨神'
}
Taylor.prototype = new Guitar()
const guitar = new Taylor()
我想買一把吉他,吉他有很多品牌,比如泰勒馬丁雅馬哈各種,精挑細選最后看中了泰勒這個吉他品牌,就先定義一個子類叫泰勒,接著我們定義父類就是Guitar。
接下來就是關鍵的一步,Taylor.prototype = new Guitar(),將Guitar的實例賦給Taylor的顯式原型prototype,這樣就完成了最基本的原型鏈繼承。我們可以來試一下,再控制臺輸入以上代碼并執(zhí)行,然后
console.log(guitar.dalao)控制臺會輸出雨神大佬,在Taylor的定義里并沒有dalao的屬性,而現(xiàn)在我們卻可以輸出dalao這個屬性,就是通過原型鏈找到的,這就說明Taylor繼承了Guitar,也說明了雨神不僅是泰勒dalao,不管任何品牌吉他的都是dalao,是我等菜雞膜拜的大神。
好了,言歸正傳,這種原型鏈的方式也有缺點,比如如果父類的屬性是一個引用類型,在一個子類實例中修改了這個屬性之后新創(chuàng)建的子類實例也會被永久修改了。還有就是不能直接給父類構造函數(shù)傳參,因為會影響新建實例對象。
Type 2: 構造函數(shù)的方式可以實現(xiàn),talk is cheap, show me the code.亮代碼
function Guitar (name) {
this.dalao= name
this.songs = []
}
function Taylor (dalao) {
this.name = 'Taylor'
this.price = 7777
Guitar.call(this, dalao)
}
const guitar = new Taylor('雨神')
和上面一樣,我們改成構造函數(shù)的方式實現(xiàn)繼承,關鍵的一步,Guitar.call(this, '雨神'),改變了父類Guitar的執(zhí)行上下文this指向,讓this指向子類,換句話說就是把父類構造函數(shù)在子類構造函數(shù)里執(zhí)行一遍。而且解決了之前原型鏈繼承存在的問題,一個就是不能直接父類構造函數(shù)傳參,我們給Guitar定義了一個形參name,在new Taylor('雨神')里我們傳入雨神這個實參,然后我們和上面一樣在控制臺輸出console.log(guitar.dalao)控制臺也一樣會輸出雨神大佬,然后我們可以做下改動,Guitar.call(this, '小老弟60'),重復上面步驟,控制臺會輸出'小老弟60'.
第二個問題就是父類引用類型屬性,我這里放了了一個songs=[]一個空數(shù)組。然后我們給guitar實例的songs做加點東西。
guitar.songs.push('盜將行')我們年會表演的曲子,很好聽的,強烈推薦,沒聽過可以試試。然后我們新建一個Taylor的實例,const guitar222= new Taylor() console.log(guitar222.songs)
控制臺輸出一個[],發(fā)現(xiàn)之前我們的操作并沒有影響到后來新建的實例對象,這就解決了原型鏈的兩個缺點,當然構造函數(shù)模式 也有缺點,就是父類原型里定義的屬性子類是無法繼承的。
所以,我們取其精華去其糟粕,把二者合二為一,誕生了第三種繼承方式,組合繼承,就是把原型鏈和構造函數(shù)組合在一起實現(xiàn)繼承。
Type 3: 組合繼承的方式可以實現(xiàn),talk is cheap, show me the code.亮代碼
function Guitar (name) {
this.dalao= name
this.songs = []
}
function Taylor (dalao) {
this.name = 'Taylor'
this.price = 7777
Guitar.call(this, dalao)
}
Guitar.prototype.band = 'HikWestlife'
Taylor.prototype = new Guitar()
Taylor.prototype.constructor = Taylor
const guitar = new Taylor('雨神')
這就是組合繼承,同時我們把Taylor.prototype.constructor的構造器指向Taylor。然而還是不夠完美,因為父類的構造函數(shù)執(zhí)行了兩次,為了更好的性能,我們發(fā)明了終極解放方案,寄生組合式繼承。
Type 4: 寄生繼承的方式可以實現(xiàn),talk is cheap, show me the code.亮代碼
function Guitar (name) {
this.dalao= name
this.songs = []
}
function Taylor (dalao) {
this.name = 'Taylor'
this.price = 7777
Guitar.call(this, dalao)
}
Guitar.prototype.band = 'HikWestlife'
Taylor.prototype = Object.create(Guitar.prototype)
Taylor.prototype.constructor = Taylor
const guitar = new Taylor('雨神')
一起來試驗一下,我們在控制臺輸出console.log(guitar.band)發(fā)現(xiàn)會輸出"HikWestlife",一樣實現(xiàn)了組合繼承的功能,而且還只執(zhí)行了一次構造函數(shù)。
好了,這就是class的真面目,放假了。。過年~