02.Javascript中的繼承----Inherits

 

02.Javascript中的繼承----Inherits

本文不再過多的闡述OOP中繼承的概念,只是用原生的Javascript代碼來模擬類繼承(不是對象擴展)

類繼承:inherits

假設有已定義好的超類(父類)SuperClass和待繼承的子類SubClass,於是,可以定義如下的方法來實現類繼承

inherits方法的定義

如下的這個inherits方法,其實現思想主要參考《Pro JavaScript Design Patterns》【Ross Harmes and Dustin Diaz】

/**
 * 這個方法用來實現類繼承
 * @param {function} subClass 待繼承的子類
 * @param {function} superClass 待被繼承的父類
 * @exception {Error} 參數不合法時拋出異常
 */
var inherits = function(subClass,superClass){
    if(arguments.length !== 2){
        throw new Error("必須明確的指定子類和父類");
    }
    for(var i = 0,n = arguments.length;i < n;i++){
        if(typeof arguments[i] !== "function"){
            throw new Errorr("所給的子類和父類必須都是function");
        }
    }
    var F = function(){};
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;    
};

該方法的內部會進行嚴格的參數合法性檢查,參數必須是兩個,即一個子類,一個父類;另外還要求兩個參數都必須是function類型,否則拋出異常,宣告繼承失敗

inherits方法的使用

▲第一步
/**
 * 定義父類
 */
var SuperClass = function(){};
SuperClass.prototype = {
    name : "趙先烈",
    talk : function(){
        alert("我的名字叫" + this.name);
    }
};    

/**
 * 這裏定義子類
 */
var SubClass = function(){};    

//實施繼承
inherits(SubClass,SuperClass);

//創建子類並從調用從子類繼承過來的方法
var oSub = new SubClass();
oSub.talk();    //這裏輸出:我的名字叫趙先烈

從程序的執行結果可以看出,這種繼承方法是將父類中的全部內容(除構造器以外)拷貝到子類中來,順利的完成了類繼承。

▲第二步
/**
 * 這裏定義父類
 */
var SuperClass = function(){
    this.name = "趙先烈";
    this.talk = function(){
        alert("我的名字叫" + this.name);
    };
};

/**
 * 這裏定義子類
 */
var SubClass = function(){
    //這是一個空類
};

//實施繼承
inherits(SubClass,SuperClass);

//創建子類對象,並調用從父類繼承過來的方法
var oSub = new SubClass();
oSub.talk();    //按照繼承的概念,這裏應該輸出:我的名字叫趙先烈

程序真正執行後,才發現發生異常了,原因:在oSub實例中不存在talk方法。不是已經通過inherits方法實現繼承了麼,爲什麼會沒有這個 方法呢?探究其原因,是因爲在inherits的內部,只是將SuperClass的原型鏈原樣的拷貝給了SubClass,而不在SuperClass 原型鏈中的屬性及方法,子類就拿不到了。

那麼,既要支持第一種繼承,也要能滿足第二種,我們只能再次對inherits方法進行升級了,將其改爲如下形式:

/**
 * 這個方法用來實現類繼承
 * @param {function} subClass 待繼承的子類
 * @param {function} superClass 待被繼承的父類
 * @exception {Error} 參數不合法時拋出異常
 */
var inherits = function(subClass,superClass){
    if(arguments.length !== 2){
        throw new Error("必須明確的指定子類和父類");
    }
    for(var i = 0,n = arguments.length;i < n;i++){
        if(typeof arguments[i] !== "function"){
            throw new Errorr("所給的子類和父類必須都是function");
        }
    }
    subClass.prototype = new superClass();
    subClass.prototype.constructor = subClass;
};

經過這樣的改動,第一步和第二步中的情況就都能順利的正常的執行了。

▲第三步

如果在第二步的基礎上,將代碼中的SubClass.prototype改爲如下形式:

SubClass.prototype = {
    walk : function(){ 
        alert("偶也,我可以走路了哎");
    },
    talk : function(){
        alert("我的名字不叫" + this.name);
    }

};

再執行如下代碼:

inherits(SubClass,SuperClass);

var oSub = new SubClass();
oSub.talk();    //這裏仍然輸出:我的名字叫趙先烈
//重點在下面這句
oSub.walk();    //這裏會拋出異常,告訴我們,walk方法不存在

分析這個結果,oSub.talk()的輸出應該爲:我的名字不叫趙先烈。並且oSub.walk()也應該有輸出,程序應該正常執行纔對。但是,爲什麼會有這樣的運行結果呢?

這到底是爲什麼呢?相信你一定早就發現了,在inherits方法中有這樣一句關鍵的代碼:

subClass.prototype = new superClass();

這裏已經告訴我們,原來,子類中的原型鏈已經被完全替換了,其實仔細說起來,這樣做是有違繼承的原則的(一般不都是子類覆蓋父類麼?怎麼 反過來了呢)。

但是這樣的問題我們始終要解決,必須讓這個所謂的繼承能同時滿足以上三種情況都能正常執行。苦思冥想後,決定改成這樣:

/**
 * 這個方法用來實現類繼承
 * @param {function} subClass 待繼承的子類
 * @param {function} superClass 待被繼承的父類
 * @exception {Error} 參數不合法時拋出異常
 */
var inherits = function(subClass,superClass){
    if(arguments.length !== 2){
        throw new Error("必須明確的指定子類和父類");
    }
    for(var i = 0,n = arguments.length;i < n;i++){
       if(typeof arguments[i] !== "function"){
            throw new Errorr("所給的子類和父類必須都是function");
        }
    }

    var oSuper = new superClass();
    for(var key in oSuper){
        if(!subClass.prototype[key]){
            subClass.prototype[key] = oSuper[key];
        }
    }
    subClass.prototype.constructor = subClass;
};

OK,通過這樣的升級,再次運行上面的代碼,順利通過了。

上面這個通過兩次升級的inherits方法也是目前比較穩定的版本了,在後續的文章中所指的inherits方法,就是這個了。

本文旨在共同探討Javascript中類的繼承方式,只是其中的一種模擬方式,模擬之不當,還請見諒。

歡迎提出寶貴的升級建議。

 

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