最近在準備面試灯蝴,js繼承真的好亂鴨鴨鴨鴨,整理一下~希望可以記得妙黍!
(參考:https://blog.csdn.net/caijixin/article/details/78295676
https://juejin.im/entry/5bcb2f695188255c2f425251)
1. 借用構(gòu)造函數(shù)繼承
- 通過call惹谐、apply方法,使用父類的構(gòu)造函數(shù)來增強子類實例,等同于復制父類的實例給子類(不使用原型)
- SuperType.call(this);創(chuàng)建子類實例時調(diào)用SuperType構(gòu)造函數(shù)筏餐,于是SubType的每個實例都會將SuperType中的屬性復制一份开泽。
function SuperType() {
this.colors = ["red","blue","green"];
}
function SubType() {
//繼承了SuperType --重新創(chuàng)建SuperType構(gòu)造函數(shù)屬性的副本
SuperType.call(this);
}
ar instance1 = newe SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"red,blue,green,black"
缺點:
- 只能繼承父類的實例屬性和方法,不能繼承原型上的屬性或方法
- 每個子類都有父類實例的副本魁瞪,沒能做到復用穆律,影響性能
優(yōu)點
- 可以傳參,SuperType.call(this,"Nicholas");
2.原型鏈方法
- 利用原型鏈來實現(xiàn)繼承导俘,超類的一個實例作為子類的原型
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){}
SubType.prototype = new SuperType();
SubType.prototype.constructor=SubType;
- SubType.prototype.constructor=SubType;如果沒有這句SubType.prototype.constructor會指向SuperType
缺點:
- 如果父類包含引用類型的屬性峦耘,那么子類所有實例都會共享該屬性。
- 在創(chuàng)建子類型的實例時旅薄,不能向超類的構(gòu)造函數(shù)中傳遞傳遞參數(shù)
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){}
SubType.prototype = new SuperType();
SubType.prototype.constructor=SubType;
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green,black"
3.組合繼承方法
- 組合上面兩種方法就是組合繼承方法辅髓。用原型鏈繼承實現(xiàn)對原型屬性和方法的繼承,借用構(gòu)造函數(shù)繼承方法實現(xiàn)對實例屬性的繼承少梁。
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
// 繼承屬性
// 第二次調(diào)用SuperType()
SuperType.call(this, name);
this.age = age;
}
// 繼承方法
// 構(gòu)建原型鏈
// 第一次調(diào)用SuperType()
SubType.prototype = new SuperType();
// 重寫SubType.prototype的constructor屬性洛口,指向自己的構(gòu)造函數(shù)SubType
SubType.prototype.constructor = SubType;
var instance1 = new SubType("Nicholas", 29);
缺點:
- 實際上子類上會擁有超類的兩份屬性,只是子類的屬性覆蓋了超類的屬性
(第一次調(diào)用SuperType()給SubType.prototype寫入兩個屬性name凯沪,color第焰。給instance1寫入兩個屬性name,color)
4.原型式繼承
- 利用一個空對象作為中介妨马,將某個對象直接賦值給空對象構(gòu)造函數(shù)的原型挺举。
function object(obj){
function F(){}
F.prototype=obj;
return new F()
}
object()對傳入其中的對象執(zhí)行了一次淺復制,將構(gòu)造函數(shù)F的原型直接指向傳入的對象烘跺。
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
ES5中存在Object.create()的方法湘纵,能夠代替上面的object方法
缺點
- 原型鏈繼承多個實例的引用類型屬性指向相同,存在篡改的可能
- 無法傳遞參數(shù)
優(yōu)點
- 可以繼承非構(gòu)造函數(shù)(以上例子就是)
5.寄生式繼承
- 在原型式繼承的基礎(chǔ)上滤淳,增強對象瞻佛,返回構(gòu)造函數(shù)。
function createAnother(original){
var clone = object(original); // 通過調(diào)用 object() 函數(shù)創(chuàng)建一個新對象
clone.sayHi = function(){ // 以某種方式來增強對象
alert("hi");
};
return clone; // 返回這個對象
}
- 函數(shù)的主要作用是為構(gòu)造函數(shù)新增屬性和方法,以增強函數(shù)
缺點
- 同原型繼承
6.寄生組合繼承
- 結(jié)合借用構(gòu)造函數(shù)傳遞參數(shù)和寄生模式實現(xiàn)繼承
function inheritPrototype(subType, superType){
var prototype=Object.create(surperType.prototype);// 創(chuàng)建對象伤柄,創(chuàng)建父類原型的一個副本
prototype.constructor=subType;// 增強對象绊困,彌補因重寫原型而失去的默認的constructor 屬性
subType.prototype=prototype;// 增強對象,彌補因重寫原型而失去的默認的constructor 屬性
}
// 父類初始化實例屬性和原型屬性
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
// 借用構(gòu)造函數(shù)傳遞增強子類實例屬性(支持傳參和避免篡改)
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
/ /將父類原型指向子類
inheritPrototype(SubType, SuperType);
// 新增子類原型屬性
SubType.prototype.sayAge = function(){
alert(this.age);
}
缺點
- 完美實現(xiàn)繼承适刀,解決了組合式繼承帶兩份屬性的問題