JavaScript的幾種繼承方式


看《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上面創建不必要的、多餘的屬性,同時保持原型鏈不變




參考:《JavaScript高級程序設計》(第3版)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章