借用構造函數實現繼承
function SuperType(){
this.colors = ["red","blue","green"];
}
function SubType(){
//在子類構造函數中調用父類構造函數(同時這種方式支持向父類構造函數傳參)
SuperType.call(this);
//SuperType.call(this,arg1,arg2)
//SuperType.apply(this,args)
}
作用:借用構造函數方式是在新的SubType對象上面執行SuperType中定義的初始化代碼,針對在原型中的引用類型,每一個實例都有自己的一個副本(可以清除原型中包含引用類型值的問題)
問題:僅僅是借用構造函數,無法避免構造函數模式存在的問題,方法都是在構造函數中定義,因此函數複用就無從談起了
組合繼承(經典繼承)
這種方式的思想是使用原型實現對原型屬性和方法的繼承,而通過構造函數實現對實例屬性的繼承
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}
//父類原型的屬性和方法
SuperType.prototype.SayName = function(){
alert(this.name);
}
function SubType(name,age){
//通過調用父類的構造方法繼承父類的實例屬性
SuperType.call(this,name);
//自己的實例屬性
this.age = age;
}
//通過原型方式繼承父類
SubType.prototype = new SuperType();
//重寫constructor屬性
SubType.prototype.constructor = SubType;
SubType.ptototype.sayAge = function(){
alert(this.age);
}
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優點,是javaScript中最常用的一種繼承模式。
問題:組合繼承會導致父類構造方法被調用兩次,當我們在創建子類原型的時候會調用一次,第二次是我們調用子類構造方法的時候裏面會調用一次。
原型式繼承
藉助原型可以基於已有對象創建新的對象,同時還不必因此創建自定義類型
var person = {
name:"SC",
friends:["nix","unix","windows","ubantu"]
}
function object(o){
//臨時構造函數
function F(){};
//繼承
F.prototype = o;
return new F();
}
var p1 = object(person);
p1.friends.push("p1's friends");
p1.name = "P1";
var p2 = object(person);
p2.friends.push("p2's friends");
p2.name = "P2";
console.log(p1.name);//P1
console.log(p2.name);//P2
console.log(p1.friends);//["nix", "unix", "windows", "ubantu", "p1's friends", "p2's friends"]
console.log(p2.friends);//["nix", "unix", "windows", "ubantu", "p1's friends", "p2's friends"]
上面的原型方式在ECMScript5中通過新增Object.create()方法規範化了,該方法接收兩個參數,第一個爲用作新對象原型的對象和(可選的)一個新對象定義額外屬性的對象。Object.create()方法是對對象進行一個簡單的克隆,如果對象裏面有引用類型的屬性,那麼只會複製一份引用
問題:原型式繼承同樣沒有解決引用問題
寄生式繼承
寄生式繼承思路與寄生構造函數類似,也就是創建一個僅僅用於封裝繼承過程的函數,該函數內部以某種方式來增強對象,最後再像真正的地是它做了所有的工作一樣返回對象。
//寄生式繼承
function createAnother(original){
//調用函數創建一個新的對象
var clone = object(original);
//以某種方式來增強這個對象
clone.sayHi = function(){
alert("HI");
}
return clone;
}
//上面的object()函數不是必須的,每一個能夠返回新對象的函數都可以適用這個模式
問題:可以使用寄生繼承來爲對象添加函數,會由於不能做到函數複用而降低效率,這一點會與構造函數模式類似。
寄生組合式繼承
寄生組合式繼承解決組合繼承中兩次調用父類構造函數的問題。寄生組合式繼承,也就是通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。
思路是:不必爲了指定子類的原型而調用超類的構造函數,我們所需要的無非就是超類型原型的一個副本而已,本質上,就是使用寄生繼承來繼承超類原型,然後再將結果指定給子類型的原型
function inheritPrototype(subType,superType){
//創建對象
var prototype = object(superType.prototype);
//增強對象
prototype.constructor = subType;
//指定對象
subType.prototype = prototype;
}