看《JavaScript高級程序設計》做的一些筆記
ECMAScript只支持實現繼承,不支持接口繼承(因爲函數沒有簽名)
原型鏈(實現繼承的主要方法):
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//繼承SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
var instance = new SubType();
通過原型鏈實現繼承時不能使用對象字面量創建原型方法,否則會重寫原型鏈
例如:
SubType.prototype = new SuperType();
//定義SubType的原型方法
SubType.prototype = { //這樣定義會使上面那行代碼無效
};
所有函數的默認原型都是Object的實例,因此SuperType.prototype中的[[Prototype]]會指向Object.Prototype
問題:
原型變成另一個類型的實例,原來的實例屬性就變成原型屬性了,因此包含引用類型值的屬性會被所有SubType實例共享(例如數組)
借用構造函數:
在子類型的構造函數中使用call()或apply()調用超類型的構造函數function SuperType(){
this.colors = [];
}
function SubType(){
//繼承SuperType
SuperType.call(this);
}
可以在子類型構造函數中向超類型構造函數傳遞參數
問題:
方法都在構造函數中定義,函數無法複用(類似構造函數模式);在超類型原型中定義的方法對子類型不可見
組合繼承(常用繼承模式):
將原型鏈和借用構造函數組合到一塊(類似組合使用構造函數模式和原型模式)用原型鏈實現對原型屬性和方法的繼承,用借用構造函數實現對實例屬性的繼承
function SuperType(name){
this.name;
this.colors = [];
}
SuperType.prototype.sayName = function(){};
function SubType(name, age){
//繼承屬性
SuperType.call(this, name);
this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){};
var instance = new SubType('myName', 66);
問題:
無論什麼情況下都會調用兩次超類型構造函數
同時,父類構造函數中的屬性會被繼承到子類的原型上
原型式繼承:
基於已有的對象創建新對象,同時還不必因此創建自定義類型function object(o){
function F(){}
F.prototype = o;
return new F();
}
var person = {
name:'myName',
friends:[]
};
var anotherPerson = object(person);
anotherPerson.name = 'anotherName';
ECMAScript5通過Object.create()規範原型式繼承
問題:
與使用原型模式一樣,包含引用類型的值會共享
寄生式繼承:
將繼承過程封裝成函數,並增強對象function createAnother(original){
var clone = object(original);
clone.sayHi = function(){};
return clone;
}
var person = {};
var anotherPerson = createAnother(person);
anotherPerson.sayHi();
問題:
不能做到函數複用,降低效率,與構造函數模式類似
寄生組合式繼承:
使用寄生式繼承來繼承超類型的原型,再將結果指定給子類型的原型function inheritPrototype(subType, superType){ //參數爲兩個類型的構造函數
var prototype = object(superType.prototype);
prototype.constructor = subType; //爲創建的副本添加因重寫原型而失去的constructor屬性
subType.prototype = prototype;
}
function SuperType(name){
this.name = name;
this.colors = [];
}
SuperType.prototype.sayName = function(){};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){};
只調用了一次SuperType的構造函數,並且避免了在SubType.prototype上面創建不必要的、多餘的屬性,同時保持原型鏈不變