JS 繼承(三)寄生組合式繼承
JS 繼承(二)中說(shuō)了組合繼承的模式,這種模式看起來(lái)似乎不錯(cuò)的樣子,那么它有什么缺點(diǎn)呢?
缺點(diǎn):父類的構(gòu)造函數(shù)運(yùn)行了兩遍,并且不能多繼承。
第一遍,把父類的實(shí)例賦值給子類的prototype屬性,目的是讓子類的實(shí)例繼承父類原型對(duì)象的方法。
第二遍,實(shí)例化子類的時(shí)候,new Man()會(huì)執(zhí)行Man的構(gòu)造函數(shù),而Man構(gòu)造函數(shù)里面有Person.call(this,...)語(yǔ)句,導(dǎo)致Person構(gòu)造函數(shù)執(zhí)行第二次,它的目的是為了給每個(gè)子類實(shí)例對(duì)象添加屬性。
為了更優(yōu)化組合繼承的方式,又發(fā)明了一種新的繼承方法:寄生組合式繼承。
它的目的是去掉第一遍父類構(gòu)造函數(shù)的執(zhí)行,只保留第二次的。
那么怎么把父類的原型對(duì)象給子類呢?
簡(jiǎn)單,把父類的原型對(duì)象拷貝一份,再把拷貝賦值給子類構(gòu)造函數(shù)的prototype屬性。
所以寄生組合繼承并不是使用原型鏈的原理達(dá)成繼承效果的,而是借用構(gòu)造函數(shù) + 拷貝對(duì)象的方式實(shí)現(xiàn)繼承。
代碼:
function Person (name,age) {
this.name = name;
this.age = age;
this.friends = ['LiLei','HanMeiMei'];
console.log('call this:', this)
}
Person.prototype.sayWords = function(des) {
console.log(des+' say words:', this.name,this.age, this.friends.toString());
}
function Man (name, age) {
this.name = name;
Person.call(this,name, age);
}
function inert (SubClass, SuperClass) {
let protoCopy = Object.assign({},SuperClass.prototype);
protoCopy.constrouctor = SubClass;
SubClass.prototype = protoCopy;
}
inert(Man, Person);
let m1 = new Man('tom', 12);
m1.friends.push('Green');
m1.sayWords("Person -> tom 1");
console.log("m1:", m1);
console.log("m1.__proto__:",m1.__proto__);
console.log('----------------')
let m2 = new Man('LiLei',13);
m2.sayWords("Person -> LiLei 2");
console.log("m2:", m2);
console.log("m2.__proto__:",m2.__proto__);
很明顯,這樣拷貝對(duì)象會(huì)導(dǎo)致同樣的屬性方法會(huì)有兩套,父類的原型對(duì)象一套,子類的原型一套,但是優(yōu)點(diǎn)也明顯,因?yàn)槭强截悓?duì)象屬性的方式繼承,所以它可以多繼承。
代碼如下:
function Person (name,age) {
this.name = name;
this.age = age;
this.friends = ['LiLei','HanMeiMei'];
console.log('call this:', this)
}
Person.prototype.sayWords = function(des) {
console.log(des+' say words:', this.name,this.age, this.friends.toString());
}
function Teacher (subject) {
this.subject = subject;
}
Teacher.prototype.sayWords = function() {
console.log("I am a teacher.", this.subject);
}
Teacher.prototype.subjectFuc = function () {
console.log('subject:',this.name, this.subject);
}
function Man (name, age, subject) {
this.name = name;
Person.call(this,name, age);
Teacher.call(this, subject);
}
function inert (SubClass, SuperClass) {
let protoCopy = Object.assign(SubClass.prototype,SuperClass.prototype);
console.log('protoCopy是拷貝一個(gè)SuperClass.prototype對(duì)象:',!(protoCopy == SuperClass.prototype), protoCopy);
protoCopy.constrouctor = SubClass;
SubClass.prototype = protoCopy;
}
inert(Man, Person);
inert(Man, Teacher);
let m1 = new Man('tom', 12, 'Math');
m1.friends.push('Green');
m1.sayWords("Person -> tom 1");
console.log('----------------')
let m2 = new Man('LiLei',13, 'chinese');
m2.sayWords("Person -> LiLei 2");
m2.subjectFuc();