JavaScript 最常用的五種繼承方式

繼承是OO語言中的一個最爲人津津樂道的概念。下面分別來細數一下JavaScript中最常用的五種繼承方式:

一、原型鏈

實現原型鏈有一種基本模式,其代碼大致如下:

function SuperType(){
	// 超類型的構造函數
}
function SubType(){
	// 子類型的構造函數
}
SubType.prototype = new SuperType();  // 原型鏈繼承方式
var instance = new SubType();

原型鏈繼承存在的問題:

  • 超類型的實例屬性變成子類型的原型屬性導致超類型中的引用類型的實例屬性被所有子類型共享,一個子類型更改其屬性會影響到其它子類型。
  • 在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。

因此實踐中很少會單獨使用原型鏈。

二、借用構造函數

這種技術的基本思想相當簡單,即在子類型構造函數的內部調用超類型構造函數。如下所示:

function SuperType(){
	// 超類型的構造函數
}
function SubType(){
	SuperType.call(this);  // 借用構造函數繼承方式
}
var instance = new SubType();

借用構造函數繼承存在的問題:

  • 方法都在構造函數中定義,函數複用無從談起。
  • 在超類型的原型中定義的方法,對子類型而言是不可見的。

考慮到這些問題,借用構造函數的技術也是很少單獨使用的。

三、組合繼承

組合繼承指的是將原型鏈和借用構造函數的技術組合到一塊,從而發揮兩者之長的一種繼承模式。其背後的思路是使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承。這樣,既通過在原型上定義方法實現了函數複用,又能保證每個實例都有它自己的屬性。組合繼承的實現方法如下:

function SuperType(){
	// 超類型的構造函數
}
function SubType(){
	SuperType.call(this);  // 借用超類型的構造函數
}
SubType.prototype = new SuperType();  // 原型鏈繼承
SubType.prototype.constructor = SubType;  // 恢復指針指向
var instance = new SubType();

組合繼承避免了原型鏈和借用構造函數的缺陷,融合了它們的優點,成爲JavaScript中最常用的繼承模式。
不過,它也有自己的不足。組合繼承最大的問題就是無論什麼情況下,都會調用兩次超類型構造函數:一次是在創建子類型原型的時候,另一次是在子類型構造函數內部。這樣做導致的結果就是超類型的實例屬性既存在於子類型的實例中,又存在於子類型的原型中。

四、寄生式繼承

寄生式繼承的思路是:創建一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最後再返回增強之後的對象。以下代碼示範了寄生式繼承模式:

function createAnother(original){
	var clone = object(original);  // 通過調用函數創建一個新對象
	// 以某種方式來增強這個對象
	return clone;  // 返回這個對象
}
var person = {};
var anotherPerson = createAnother(person);

在主要考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式。
但是使用寄生式繼承來爲對象添加函數,會由於不能做到函數複用而降低效率;這一點與構造函數模式類似。

五、寄生組合式繼承

寄生組合式繼承背後的基本思路是:不必爲了指定子類型的原型而調用超類型的構造函數,我們所需的無非就是超類型原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,然後再將結果指定給子類型的原型。寄生組合式繼承的基本模式如下所示:

function inheritPrototype(subType, superType){
	var prototype = object(superType.prototype);  // 創建對象
	prototype.constructor = subType;  // 增強對象
	subType.prototype = prototype;  // 指定對象
}
function SuperType(){
	// 超類型的構造函數
}
function SubType(){
	SuperType.call(this);  // 借用構造函數
}
inheritPrototype(SubType, SuperType);
var instance = new SubType();

寄生組合式繼承的高效率體現在它只調用了一次SuperType構造函數,並且因此避免了在SubType.prototype上面創建不必要的、多餘的屬性。開發人員普遍認爲寄生組合式繼承是引用類型最理想的繼承範式。

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