1.原型鏈酬土。2.構造函數。3.組合繼承格带。4.寄生組合繼承撤缴。5.原型式。6.寄生式叽唱。
1屈呕、簡單原型鏈:
核心:拿父類實例來充當子類原型對象
優(yōu)點:簡單,易于實現
缺點:
① 修改sub1.arr后sub2.arr也變了棺亭,因為來自原型對象的 “引用屬性” 是所有實例共享的虎眨。
②創(chuàng)建子類實例時,無法向父類構造函數傳參
function Super(){
? ?this.val = 1;
? ? this.arr = [1];
}
function? Sub(){}
Sub.prototype =new ?Super();// 核心
var sub1 =new ?Sub();
sub1.val = 2;
sub1.arr.push(2);
alert(sub1.val);// 2
alert(sub1.arr);// 1, 2
var sub2 =new ?Sub();
alert(sub2.val);// 1
alert(sub2.arr);// 1, 2
2.借用構造函數
核心:借父類的構造函數來增強子類實例,等于是把父類的實例屬性復制了一份給子類實例裝上了(完全沒有用到原型)所有sub1和sub2互不干擾嗽桩。
優(yōu)點:(解決了使用原型鏈繼承的缺點岳守,同時引出了以下的缺點)
①解決了子類實例共享父類引用屬性的問題
②創(chuàng)建子類實例時,可以向父類構造函數傳參
缺點:
無法實現函數復用碌冶,每個子類實例都持有一個新的fun函數湿痢,太多了就會影響性能,內存爆炸扑庞。譬重。
function ?Super (val){
?? this.val = val;
? ?this.arr = [1];
? this.fun =function(){}
}
function Sub(val){
Super.call(this, val);// 核心
}
實例:
var sub1 =new Sub(1);
var sub2 =new Sub(2);
sub1.arr.push(2);
alert(sub1.val);// 1
alert(sub2.val);// 2
alert(sub1.arr);// 1, 2
alert(sub2.arr);// 1
alert(sub1.fun === sub2.fun);// false
3.組合繼承(最常用)
核心:把實例函數都放在原型對象上,以實現函數復用罐氨。同時還要保留借用構造函數方式的優(yōu)點臀规,通過Super.call(this);繼承父類的基本屬性和引用屬性并保留能傳參的優(yōu)點;通過Sub.prototype = new Super();繼承父類函數栅隐,實現函數復用塔嬉。
優(yōu)點:
①不存在引用屬性共享問題。
②子類實例可以向父級傳參
③函數可以進行復用
缺點:
(一點小瑕疵)子類原型上有一份多余的父類實例屬性约啊,因為父類構造函數被調用了兩次邑遏,生成了兩份,而子類實例上的那一份屏蔽了子類原型上的恰矩。。憎蛤。又是內存浪費外傅,比剛才情況好點,不過確實是瑕疵俩檬。
function ?Super(){
// 只在此處聲明基本屬性和引用屬性
? ?this.val = 1;
? ?this.arr = [1];
}
//? 在此處聲明函數
Super.prototype.fun1 =function(){};
Super.prototype.fun2 =function(){};
function Sub(){
? ?Super.call(this);// 核心
}
Sub.prototype =new Super();// 核心
var sub1 =new ?Sub(1);
var sub2 =new ?Sub(2);
alert(sub1.fun1 === sub2.fun1);// true
4.寄生組合繼承(最佳方式)
核心:用beget(Super.prototype);切掉了原型對象上多余的那份父類實例屬性
優(yōu)點:完美了
缺點:理論上沒有了(如果用起來麻煩不算缺點的話萎胰。。)
用起來麻煩是一方面棚辽,另一方面是因為寄生組合式繼承出現的比較晚技竟,是21世紀初的東西,大家等不起這么久屈藐,所以組合繼承是最常用的榔组,而這個理論上完美的方案卻只是課本上的最佳方式了
function ?beget(obj){// 生孩子函數 beget:龍beget龍,鳳beget鳳联逻。
varF =function(){};
F.prototype = obj;
return new F();
}
function Super(){
? // 只在此處聲明基本屬性和引用屬性
? ?this.val = 1;
? ?this.arr = [1];
}
//? 在此處聲明函數
Super.prototype.fun1 =function(){};
Super.prototype.fun2 =function(){};
//Super.prototype.fun3...
function Sub(){
? ?Super.call(this);// 核心
}
var proto = beget(Super.prototype);// 核心
proto.constructor = Sub;// 核心
Sub.prototype = proto;// 核心
var sub =new Sub();
alert(sub.val);
alert(sub.arr);
5.原型式
核心:用生孩子函數得到得到一個“純潔”的新對象(“純潔”是因為沒有實例屬性)搓扯,再逐步增強之(填充實例屬性)
P.S.ES5提供了Object.create()函數,內部就是原型式繼承包归,IE9+支持
優(yōu)點:從已有對象衍生新對象锨推,不需要創(chuàng)建自定義類型(更像是對象復制,而不是繼承。)
缺點:
① 原型引用屬性會被所有實例共享换可,因為是用整個父類對象來充當了子類原型對象椎椰,所以這個缺陷無可避免。
② 無法實現代碼復用(新對象是現取的沾鳄,屬性是現添的慨飘,都沒用函數封裝,怎么復用)
function ?beget(obj){ ?// 生孩子函數 beget:龍beget龍洞渔,鳳beget鳳套媚。
? var F =function(){};
? F.prototype = obj;
? return new F();
}
function Super(){
? ?this.val = 1;
? ?this.arr = [1];
}
// 拿到父類對象
var sup =new Super();
// 生孩子
var sub = beget(sup);// 核心
// 增強
? ? ? sub.attr1 = 1;
? ? ? sub.attr2 = 2;
? ? ?//sub.attr3...
? ? ? ?alert(sub.val);// 1
? ? ? ? alert(sub.arr);// 1
? ? ? ?alert(sub.attr1);// 1
6.寄生式
這名字太扯了,而且寄生式是一種模式(套路)磁椒,并不是只能用來實現繼承
核心:給原型式繼承穿了個馬甲而已堤瘤,看起來更像繼承了(上面介紹的原型式繼承更像是對象復制)
優(yōu)點:還是不需要創(chuàng)建自定義類型
缺點:無法實現函數復用(沒用到原型,當然不行)
function ?beget(obj){// 生孩子函數 beget:龍beget龍浆熔,鳳beget鳳本辐。
var F =function(){};
? ?F.prototype = obj;
? ?return new F();
}
function Super(){
? ?this.val = 1;
? ?this.arr = [1];
}
function getSubObject(obj){
? ?// 創(chuàng)建新對象
? var clone = beget(obj);// 核心
? // 增強
? ?clone.attr1 = 1;
? clone.attr2 = 2;
? return clone;
}
var sub = getSubObject(newSuper());
alert(sub.val);// 1
alert(sub.arr);// 1
alert(sub.attr1);// 1