參考《JavaScript 高級程序設計(第3版)》
在 JavaScript 中實現繼承,有兩種基本方法,一種是使用原型鏈,令子類的原型是父類的一個對象;另一種是借用構造方法,在子類的構造方法中使用call方法或apply方法調用父類的構造函數。但這兩種方法基本上都很少單獨使用,而是採用組合式的繼承。
一、原型鏈
//定義父類
function Person(){
this.type = "person";
}
//定義父類的方法
Person.prototype.getType = function(){
return this.type;
}
//定義子類
function Man(){
this.type = "man";
this.name = "Jack";
}
//利用原型鏈實現繼承
Man.prototype = new Person();
//定義子類的方法
Man.prototype.getName = function(){
return this.name;
}
//重寫父類的方法
Man.prototype.getType = function(){
return this.type;
}
利用原型鏈實現繼承最重要的是:子類.prototype = new 父類();
特別需要注意的是定義子類的方法或是重寫父類方法必須在利用原型鏈實現繼承之後,而且不可使用字面量添加方法,否則會重寫原型,也就沒了繼承。
原型鏈方法主要存在的問題有兩點:
1、創建子類對象時無法向父類構造函數傳遞參數,因爲只有子類的原型纔有調用父類的構造函數。
2、如果父類構造函數中定義了引用類型,那麼這個引用類型會成爲子類原型的一個屬性,也就成爲了所有子類的一個共享屬性,一個子類對象對該屬性的修改會影響所有的子類對象。
二、借用構造函數
//定義父類
function Person(name){
this.name = name;
this.category = ["man","women"];
}
//定義子類
function Man(){
//調用父類構造方法實現繼承,還可實現傳參
Person.call(this,"Jack");
}
借用構造函數就是在子類構造函數中調用父類構造函數,這樣一個直接的好處就是創建子類對象的時候可以傳參數,而且父類構造函數中定義的引用類型屬性會成爲各個子類對象的獨佔屬性。
但是,借用構造函數存在的問題是父類原型中定義的方法在子類中是不可見的,也就無法實現重寫。
三、組合繼承
將原型鏈繼承和借用構造函數方法繼承的優點結合起來,揚長避短。
分爲以下5個主要步驟:
1、將私有屬性定義在構造方法中
2、將共有方法定義在原型中
3、子類構造方法利用call或apply調用父類構造方法
4、子類的原型指向父類對象
5、子類原型的constructor屬性指向子類的構造方法
//定義父類構造方法,包括私有屬性
function Person(name){
this.name = name;
this.category = ["man","woman"];
}
//定義父類的共有方法
Person.prototype.sayName = function(){
alert(this.name);
}
//定義子類的構造方法
function man(name, age){
//調用父類的構造方法
Person.call(this,name);
this.age = age;
}
//定義子類的原型
Man.prototype = new Person();
//定義子類原型的constructor屬性
Man.prototype.constructor = Man;
//定義子類的方法
Man.prototype.sayAge = function(){
alert(this.age);
}
Man的對象也可調用sayName方法。