1、原型鏈繼承
- 原理:通過原型鏈將子類的原型指向父類的實例
function FarType(name) {
this.name = name
this.color = ['red', 'blue', 'yellow']
}
FarType.prototype.showName = function() {
console.log(this.name)
}
function SonType(age) {
this.age = age
}
SonType.prototype = new FarType();
SonType.prototype.showAge = function() {
console.log(this.age)
}
- 測試
let son_1 = new SonType(12)
son_1.color.push('black')
console.log(son_1.color) //["red", "blue", "yellow", "black"]
son_1.showAge() //12
son_1.showSex() //male
son_1.showName() //undefined
let son_2 = new SonType(22)
console.log(son_2.color) //["red", "blue", "yellow", "black"]
son_2.showAge() //22
son_2.showSex() //male
son_2.showName() //undefined
-
缺點
- 父類包含引用類型值的原型陵叽,它會被所有實例共享狞尔,因為子類的prototype指向了父類的實例,父類實例中的color指針一直保持不變
- 創(chuàng)造子類實例時巩掺,不能向父類的構(gòu)造函數(shù)中傳遞參數(shù)(參考父類中的name并沒有被賦值)
-
優(yōu)點
- 子類可以通過原型鏈共享父類原型中的方法
-
注意事項
- 子類原型添加方法的代碼一定要放在子類替換原型的語句之后偏序,否則子類原型的方法還是添加到了默認的子類原型中。
2胖替、借用構(gòu)造函數(shù)繼承
- 原理:在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用父類構(gòu)造函數(shù)研儒,使用apply()和call()方法將this指向子類
function FarType(name) {
this.name = name
this.sex = 'male'
this.color = ['red', 'blue', 'yellow']
}
FarType.prototype.showName = function() {
console.log(this.name)
}
FarType.prototype.showSex = function() {
console.log(this.sex)
}
function SonType(age, name) {
FarType.call(this, name)
this.age = age
}
SonType.prototype.showAge = function() {
console.log(this.age)
}
- 測試
let son_1 = new SonType(12, 'son_1')
son_1.color.push('black')
console.log(son_1.name) //son_1
console.log(son_1.color) //["red", "blue", "yellow", "black"]
son_1.showAge() //12
// son_1.showSex() //Uncaught TypeError: son_1.showSex is not a function
let son_2 = new SonType(22, 'son_2')
console.log(son_2.name) //son_2
console.log(son_2.color) //["red", "blue", "yellow"]
son_2.showAge() //22
son_2.showSex() //Uncaught TypeError: son_2.showSex is not a function
-
缺點
- 子類的原型無法通過原型鏈到父類原型豫缨,即父類原型中的方法無法使用(如果想使用方法,只能定義在父類中)
-
優(yōu)點
- 字實例都會有自己的數(shù)據(jù)的副本端朵,引用類型在每個子類型實例中都已單獨的一個副本好芭,不會相會影響
- 創(chuàng)造子類實例時,可以向父類的構(gòu)造函數(shù)中傳遞參數(shù)(參考子類實例中的那么屬性)
3冲呢、組合繼承(原型鏈繼承和借用構(gòu)造函數(shù)繼承結(jié)合)
- 原理:將原型鏈繼承和借用構(gòu)造函數(shù)繼承組合到一起舍败。使用原型鏈繼承實現(xiàn)對原型屬性和方法的繼承,用借用構(gòu)造函數(shù)繼承實現(xiàn)對父實例屬性的繼承敬拓。這樣既通過在原型上定義方法實現(xiàn)了函數(shù)復用邻薯,又能保證每個實例都有自己的屬性
function FarType(name) {
this.name = name
this.sex = 'male'
this.color = ['red', 'blue', 'yellow']
}
FarType.prototype.showName = function() {
console.log(this.name)
}
FarType.prototype.showSex = function() {
console.log(this.sex)
}
function SonType(age, name) {
FarType.call(this, name)
this.age = age
}
SonType.prototype = new FarType();
SonType.prototype.showAge = function() {
console.log(this.age)
}
- 測試
let son_1 = new SonType(12, 'son_1')
son_1.color.push('black')
console.log(son_1.name) //son_1
console.log(son_1.color) //["red", "blue", "yellow", "black"]
son_1.showAge() //12
son_1.showSex() //male
let son_2 = new SonType(22, 'son_2')
console.log(son_2.name) //son_2
console.log(son_2.color) //["red", "blue", "yellow"]
son_2.showAge() //22
son_2.showSex() //male
-
缺點
1、會調(diào)用兩次超類型構(gòu)造函數(shù)乘凸,一次是在創(chuàng)建子類型原型的時候厕诡,一次是在子類型構(gòu)造函數(shù)的內(nèi)部,占用內(nèi)存营勤。
2灵嫌、由于調(diào)用了兩次父構(gòu)造函數(shù)在子類實例的原型對象上會有冗余的屬性存在 -
優(yōu)點
1.既可以繼承父類原型中的方法和屬性,也可以為父構(gòu)造函數(shù)傳遞參數(shù)冀偶,保證每個子實例都有自己的屬性(副本)
4醒第、原型繼承
- 原理:不用嚴格意義上的構(gòu)造函數(shù),借助原型可以根據(jù)已有的對象創(chuàng)建新對象进鸠,不必因此創(chuàng)建自定義類型
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
- 測試
let animals = {
dog : 12,
cat : 20,
arr : [1,2,3]
}
let res_1 = obj(animals)
res_1.cat = 50
res_1.arr.push(4)
console.log(res_1)
let res_2 = obj(animals)
console.log(res_2)
- 注意:原型繼承實際上是創(chuàng)建了animals 的兩個副本稠曼,因為arr的指針沒有發(fā)生變化,所以會出現(xiàn)上圖arr在兩個對象中相同的情形
-
規(guī)范: 可以參考es5中
Object.create(obj, des)
方法客年。第一個參數(shù)obj是原型對象霞幅,第二個參數(shù)des是生成對象的屬性描述符descriptors
5、寄生式繼承
- 原理:寄生式繼承是與原型式繼承緊密相關(guān)的一種思路量瓜,它創(chuàng)造一個僅用于封裝繼承過程的函數(shù)司恳,在函數(shù)內(nèi)部以某種方式增強對象,最后再返回對象绍傲。其實就是原型繼承封裝了一層而已
function parasitic(original){
let clone = obj(original)
clone.sayHello = function(){
console.log("hello, World");
};
return clone
}
console.log(parasitic({a:1}))
6扔傅、寄生組合式繼承(終極目標)
- 原理:通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法烫饼,不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù)猎塞,只需要超類型的一個副本。本質(zhì)上杠纵,就是使用寄生式繼承來繼承超類型的原型荠耽,然后再將結(jié)果指定給子類型的原型(這個理解了,就ok)
function inheritPrototype(sonType,farType){
let prototype = obj(farType);
prototype.constructor = sonType;
sonType.prototype = prototype ;
}
- 測試
function FarType(name){
this.name = name;
this.color = ["red","green","blue"];
}
FarType.prototype.sayName = function(){
console.log(this.name);
};
function SonType(name,age){
FarType.call(this,name);
this.age = age;
}
inheritPrototype(SonType,FarType.prototype);
SonType.prototype.sayAge = function(){
console.log(this.age);
};
let son_1 = new SonType('son_1',12)
son_1.color.push('black')
console.log(son_1.color) //["red", "green", "blue", "black"]
son_1.sayAge() //12
son_1.sayName() //son_1
let son_2 = new SonType('son_2',20)
console.log(son_2.color) //["red", "green", "blue"]
son_2.sayAge() //20
son_2.sayName() //son_2
- 優(yōu)點
- 只調(diào)用了一次Fartype構(gòu)造函數(shù)比藻,因此避免在SonType.prototype上創(chuàng)建不必要的铝量,多余的屬性倘屹,與此同時,原型鏈還能保持不變慢叨,還能正常使用instanceof 和isPrototypeOf()纽匙,因此,寄生組合式繼承被認為是引用類型最理想的繼承范式插爹。
結(jié)尾
哄辣。请梢。赠尾。。毅弧。气嫁。。够坐。寸宵。。元咙。梯影。。庶香。甲棍。。赶掖。感猛。。奢赂。陪白。。膳灶。咱士。。轧钓。序厉。。聋迎。脂矫。。霉晕。庭再。捞奕。。拄轻。颅围。。恨搓。院促。。斧抱。常拓。。辉浦。弄抬。。宪郊。掂恕。。弛槐。懊亡。。乎串。店枣。。灌闺。艰争。。桂对。甩卓。。蕉斜。逾柿。。宅此。机错。。父腕。弱匪。。璧亮。萧诫。斥难。。帘饶。哑诊。。及刻。镀裤。。缴饭。暑劝。。茴扁。铃岔。。峭火。。智嚷。卖丸。。盏道。稍浆。。猜嘱。衅枫。。朗伶。弦撩。。论皆。益楼。。点晴。感凤。。粒督。陪竿。。屠橄。族跛。捐康。。庸蔼。解总。。姐仅。花枫。。掏膏。劳翰。2018完了。馒疹。佳簸。