Javascript之對象的繼承


繼承是面向對象語言一個非常重要的部分。許多OOP語言都支持接口繼承和實現繼承兩種方式。接口繼承:繼承方法簽名;實現繼承:繼承實際的方法。在ECMAScript中函數是沒有簽名的,所以也就無法實現接口繼承,只能支持實現繼承。

在JavaScript中有大概六種繼承方式,它們分別是:原型鏈繼承,借用構造函數繼承,組合繼承,原型式繼承,寄生式繼承和寄生組合式繼承。下面就是對着六種繼承方式的詳細介紹。

1.原型鏈

基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。在這里還得補充一下,每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。

function BasicType() {
     this.property=true;
     this.getBasicValue = function(){
     return this.property;
      };
}
function NewType() {
     this.subproperty=false;
}
NewType.prototype = new BasicType(); 
var test = new NewType();
alert(test.getBasicValue());   //true

由上面可以知道,其本質上是重寫了原型對象,代之一個新類型的實例。在通過原型鏈繼承的情況下,要訪問一個實例屬性時,要經過三個步驟:1搜索實例;2搜索NewType.prototype;3搜索BasicType.prototype,此時才找到方法。如果找不到屬性或者方法,會一直向上回溯到末端才會停止。要想確定實例和原型的關系,可以使用instanceof和isPrototypeof()測試,只要是原型鏈中出現過的原型,都可以說是該原型鏈所派生實例的原型。還有一點需要注意,通過原型鏈實現繼承時,不能使用對象字面量創建原型方法,因為這時會重寫原型鏈,原型鏈會被截斷。

2借用構造函數繼承

其大體思路是,在子類型構造函數的內部調用超類型構造函數。

function BasicType(name) {
this.name=name;
this.color=["red","blue","green"]; } function NewType() { BasicType.call(this,"syf");
this.age=23; }
var test = new NewType();

alert(text.name);
//syf
alert(text.age);   //23

這種繼承實現方式有一種優勢就是,可以在子類型構造函數中向超類型構造函數中傳遞參數,其缺點是不能進行函數復用。

3組合式繼承     

組合繼承就是將原型鏈和借用構造函數繼承模式結合起來,從而具有二者優勢的方法。其理念是使用原型鏈實現對原型屬性和方法的繼承,通過借用構造函數來實現對實例屬性的繼承。

function BasicType(name) {
     this.name=name;
     this.colors=["red","blue","green"];
}
BasicType.prototype.sayName=function(){
     alert(this.name);
}
function NewType(name,age) {
     BasicType.call(this,name);
     this.age=age;
}
var test = new NewType("syf","23");
test.colors.push("black");
alert(test.colors);  //"red,blue,green,black"
alert(test.name);   //"syf"
alert(test.age);   //23

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

4原型式繼承

原型鏈繼承和原型式繼承只有一字之差,但他們的機理還是有所差別的。原型式繼承是借助於已有的對象來創建新對象,也就是必須有一個對象可以作為另外一個對象的基礎。繼承方式函數表達為:

function object (o) {
    function F(){}
    F.prototype = o;
    return new F();
}

我們可以在o的基礎上進行修改,來創建特定的對象。直觀上來說,其與原型鏈繼承最大的不同之處就是沒有使用new操作符。

5寄生式繼承

寄生式繼承的思路與寄生構造函數和工廠模式類似,即創建一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來繼承對象,最后再返回對象。具體為:

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

在主要考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式。使用寄生式繼承來為對象添加函數,函數復用率低。

6寄生組合式繼承

上面提到組合式繼承,其也是JS里最常用的基礎模式。但,由於其會調用兩次超類型的構造函數:一次在創建子類型的時候,另一次是在子類型構造函數內部。也就是子類型最終會包含超類型的全部實例屬性,但在調用子類型構造函數時會重寫這些屬性。寄生組合式繼承的大致思路為:通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。也就是說,不必為了指定子類型的原型而調用超類型的構造函數,我們需要的是超類型原型的一個副本而已。本質上就是,使用寄生式繼承來繼承超類型的原型,然后再將結果指定給子類型的原型。基本模式如下:  

function inheritPrototype (subType ,superType){
      var prototype = object (superType.prototype);  //創建對象,創建超類型原型的一個副本
       prototype.constructor = subType;   //增強對象,為創建的副本添加constructor屬性
subType.prototype = prototype; //指定對象,將新創建的對象賦值給子類型的原型
}

由於寄生組合式繼承彌補了組合式繼承缺點,所以也被眾多開發者認為是最理想的繼承方式。

以上就是JS里的六種繼承方式的介紹,在編程實踐中具體選取哪種方式還要根據當時情況來判定,適合的才是最好的,並一定非得使用組合式繼承或者寄生組合式繼承來完成繼承。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM