1. 程式人生 > >13 對象 - 繼承

13 對象 - 繼承

() property 缺陷 als strong this bject gre blue

許多 OO 語言都支持兩種繼承方式:接口繼承實現繼承。接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。

由於JS函數沒有簽名,在 ECMAScript 中無法實現接口繼承。 ECMAScript 只支持實現繼承,而且其實現繼承主要是依靠原型鏈來實現的。

1 繼承的原理

繼承是通過創建 SuperType 的實例,並將該實例賦給SubType.prototype 實現的。

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(); alert(instance.getSuperValue()); //true

關系圖如下:

技術分享

拿上面的例子來說,調用instance.getSuperValue()會經歷三個搜索步驟:

1)搜索實例;

2)搜索 SubType.prototype;

3)搜索 SuperType.prototype,最後一步才會找到該方法。

在找不到屬性或方法的情況下,搜索過程總是要一環一環地前行到原型鏈末端才會停下來。

事實上,前面例子中展示的原型鏈還少一環。我們知道,所有引用類型默認都繼承了 Object,而這個繼承也是通過原型鏈實現的。

所以,完整的原型鏈應該如下:

技術分享

由於原型鏈的關系,我們可以說 instance 是 Object、 SuperType 或 SubType 中任何一個類型的實例。

技術分享

原型鏈雖然很強大,可以用它來實現繼承,但它也存在一些問題。

主要是由於共享導致的。如下代碼:

function SuperType(){
    this.colors = ["red", "blue", "green"];
}
function SubType(){
}

//繼承了 SuperType
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green,black"

因為這種缺陷,實踐中很少會單獨使用原型鏈。

2 借用構造函數(經典繼承)

function SuperType(){
    this.colors = ["red", "blue", "green"];
}
function SubType(){
    //繼承了 SuperType
    SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"

解讀:

第一, new SubType()會創建一個新對象。

第二, SubType()中的this指向這個新對象。

第三, 在這個新對象中執行SuperType()函數,也相當於在這個新對象中運行SuperType()函數,也就給這個新對象加了一個屬性colors數組。

第四, 將這個新對象名為為instance1。

這種方法的缺陷:方法都在構造函數中定義,因此函數復用就無從談起了。考慮到這些問題,借用構造函數的技術也是很少單獨使用的。

3 組合繼承

指的是將原型鏈和借用構造函數的技術組合到一塊,從而發揮二者之長的一種繼承模式。

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();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29

var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

組合繼承避免了原型鏈和借用構造函數的缺陷,融合了它們的優點,成為 JavaScript 中最常用的繼承模式。

13 對象 - 繼承