寄生組合式繼承,從名字看就可以理解為寄生式繼承和組合式繼承的結(jié)合版,是開發(fā)人員普遍認為寄生組合式繼承是引用類型最理想的繼承范式。要了解寄生組合式繼承首先從寄生式繼承和組合式繼承。
組合式繼承
組合式繼承將原型鏈和構(gòu)造函數(shù)的技術(shù)組合到一起,結(jié)合兩者的優(yōu)點,通過原型鏈實現(xiàn)對原型屬性和方法的繼承以及借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承。擁有以下的優(yōu)點
- 父類的方法可以被復(fù)用
- 父類的引用屬性不會被共享
- 子類構(gòu)建實例時可以向父類傳遞參數(shù)
不過組合式繼承中兩次調(diào)用了父類構(gòu)造函數(shù),
// 創(chuàng)建父類
let parent = function(name) {
// 父類型的自有屬性
this.name = name;
this.hobbies = ['tennis','music','photography']
}
// 添加父類方法
parent.prototype = {
getName() { console.log(this.name) }
}
// 創(chuàng)建子類
let son = function(name,sex) {
//構(gòu)造函數(shù)式繼承父類屬性,這里是第二次調(diào)用父類構(gòu)造函數(shù)
parent.call(this, name);
// 添加子類自己的私有屬性
this.sex = sex;
}
// 這里是類式繼承子類原型繼承父類,是第一次調(diào)用父類構(gòu)造函數(shù)
son.prototype = new parent();
// 將構(gòu)造函數(shù)指向自己
son.prototype.constructor = son;
// 添加子類自己的方法
son.prototype.getsex = function () { console.log(this.sex)}
// 創(chuàng)建實例
let sub1 = new son('taec','male')
console.log(sub1)
sub1.getName()
sub1.getsex()

根據(jù)上面代碼個人理解的原型鏈如下圖所示,如果不對希望有大佬指正下

組合繼承原型鏈
寄生式繼承
創(chuàng)建一個封裝基礎(chǔ)過程的函數(shù),該函數(shù)內(nèi)部以某種方式來增強對象,最后再像真的是它做了所有工作一樣返回對象。
// 設(shè)置父類自有屬性和方法
let parent2 = {
name:'zy',
hobbies:['tennis','music','photography'],
getName:function () {console.log(this.name)}
}
// 這個方法用于創(chuàng)建一個新對象并且連接原型鏈
function object (obj) {
function F(){}
F.prototype = obj;
return new F ();
}
function createson (o,sex) {
// 傳入父類創(chuàng)建個新對象
let newson = object(o)
// 這里增強對象,添加屬性和方法
newson.sex = sex
newson.getsex = function () { console.log(this.sex) }
// 返回對象
return newson
}
let sub2 = createson(parent2,'famle')
console.log(sub2)
sub2.getName()
sub2.getsex()

寄生繼承實現(xiàn)
根據(jù)上面的代碼可以建立如下的原型鏈圖,如果不對希望有大佬指正下

寄生式繼承因為使用了一個函數(shù)以某種形式來增強對象,最后返回對象,那么復(fù)用率就不高,導(dǎo)致效率低。
寄生組合式繼承
了解了組合繼承和寄生繼承之后就是寄生式組合繼承了,它是通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈形式來繼承方法,會解決2次調(diào)用父類函數(shù)以及復(fù)用率的問題。
這里使用《JavaScript高級程序設(shè)計》中的代碼來解釋繼承的方法
// 實現(xiàn)繼承的核心函數(shù)
function inheritPrototype(subType,superType) {
function F() {};
//F()的原型指向的是superType
F.prototype = superType.prototype;
//subType的原型指向的是F()
subType.prototype = new F();
// 重新將構(gòu)造函數(shù)指向自己,修正構(gòu)造函數(shù)
subType.prototype.constructor = subType;
}
// 設(shè)置父類
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
SuperType.prototype.sayName = function () {
console.log(this.name)
}
}
// 設(shè)置子類
function SubType(name, age) {
//構(gòu)造函數(shù)式繼承--子類構(gòu)造函數(shù)中執(zhí)行父類構(gòu)造函數(shù)
SuperType.call(this, name);
this.age = age;
}
// 核心:因為是對父類原型的復(fù)制,所以不包含父類的構(gòu)造函數(shù),也就不會調(diào)用兩次父類的構(gòu)造函數(shù)造成浪費
inheritPrototype(SubType, SuperType)
// 添加子類私有方法
SubType.prototype.sayAge = function () {
console.log(this.age);
}
var instance = new SubType("Taec",18)
console.dir(instance)

繼承結(jié)果
可以看到很好的繼承了父類的方法和屬性以及自己添加屬性和方法,并且只調(diào)用了1次父類構(gòu)造函數(shù),同時保證了原型鏈的完整,是一種理想的繼承方法。下圖是自己理解的圖示,如果有錯誤希望大佬來指正

寄生組合繼承
參考了一些文章: