淺談JavaScript繼承

Javascript繼承

學事後端語言的同窗對繼承並不陌生,可是對JS繼承少量仍是有些困惑,不要試圖問我是若是知道的,其實javascript繼承主要是基於原型prototype實現的。javascript

其實當你真正瞭解了原型鏈時候,再看js繼承,其實比OOP語言更靈活、更簡單一些。接下來咱們來看看原型鏈繼承吧:java

//父類
    function Animal(){}
    //子類
    function Dog(){}
    //繼承
    Dog.prototype = new Animal();

其實,就是把子類的prototype指向父類的實例,繼承就完成了,很簡單吧。這就是原型鏈繼承
上面只是一個簡單的繼承結果,並沒有實際意義,繼承的目的就是要共享父類的屬性和方法,接下來咱們一步一步來揭開這神祕的面紗git

/**
     *
     * 父類,帶屬性
     * @constructor
     * @param name 名字
     * @param type  動物分類
     * @constructor
     */
    function Animal(name,type) {
      this.name = name || 'your name';
      this.type= type || 0;
      this.coatColor= ['white','block','yellow','brown']; //引用類型
      //函數也是引用類型
      this.speak = function () {
          console.log(this.name+' speaking .');
      }
}
    }
    
    /**
     * 爲父類新增一個方法
     * @returns {boolean}
     */
    Animal.prototype.say= function () {
         console.log('my name  is '+this.name);
    };
    
    /**
     * 子類
     * @constructor
     */
    function Dog(name) {
         this.name = name;
         this.foot= 4;
    }
    
    //實現繼承-原型鏈繼承 => (子類 -> 子類原型->父類) ;繼承 注意,繼承必需要寫在子類方法定義的前面
    Dog.prototype = new Animal();
    
    /**
     * 子類方法
     *  爲子類新增一個方法(在繼承以後,不然會被覆蓋/異常)  dog.run is not a function
     */
    Dog.prototype.run = function () {
        console.log('The '+ this.name +' was runing.');
    };
    var dog = new Dog('taiSen');
    console.log(dog.name); //dog    --子類覆蓋父類的屬性
    console.log(dog.type); // 0     --父類的屬性
    console.log(dog.foot); //4      --子類本身的屬性
    dog.say(); //my name  is taiSen    --繼承自父類的方法
    dog.run(); //The taiSen was runing. --子類本身的方法

以上,看起來咱們好像已經完成了一個完整的繼承了。可是,原型鏈繼承有一個缺點,就是屬性若是是引用類型的話,會共享引用類型 ,接下來我個Animal增長引用類型屬性this.coatColor,測試下github

//測試下
    var dog1= new Dog();
    var dog2 = new Dog();
    dog1.coatColor.push('blue');
    console.log(dog1.coatColor); // [ 'white', 'block', 'yellow', 'brown', 'blue' ]
    console.log(dog2.coatColor); // [ 'white', 'block', 'yellow', 'brown', 'blue' ]
dog1,dog2 輸出的coatColor同樣,說明引用類型屬性會被 全部實例共享--- 這就是原型鏈繼承的缺點,那麼咱們若是解決這個問題呢? 接下來咱們就要借用———— 構造函數繼承
//子類
    function Cat() {
        Animal.call(this)  // 構造函數繼承(繼承屬性)
    }
    
    //測試下
    var cat1= new Cat();
    var cat2 = new Cat();
    cat1.coatColor.push('red');
    console.log(cat1.coatColor); // [ 'white', 'block', 'yellow', 'brown', 'red' ]
    console.log(cat2.coatColor); // [ 'white', 'block', 'yellow', 'brown']

從結果看,咱們就解決了引用類型被全部實例共享的問題了。後端

注意:這裏跟 原型鏈繼承有個比較明顯的區別是並無使用 prototype繼承,而是在子類裏面執行父類的構造函數, 至關於把父類的代碼複製到子類裏面執行一遍,這樣作的另外一個好處就是能夠給父類傳參。

測試代碼:函數

/好比:
    function Pig(name) {
        Animal.call(this,name);
    }
    var pig1= new Animal('big Pig');
    var pig2 = new Animal('small Pig');
    console.log(pig1.name); // big Pig
    console.log(pig2.name); //small Pig

看起來是否是很像java,C#語言啊,以上構造函數解決了引用類型被全部實例共享的問題。測試

注意: 正由於構造函數解決了解決了引用類型被全部實例共享的問題,致使了一個相對很矛盾的問題出現了,—————— 函數也是 引用類型,函數也沒辦法共享了.也就是說,每一個實例裏面的函數,雖然功能同樣,可是卻不是同一個函數,就至關於咱們每實例化一個子類,就複製了一遍的函數代碼。
//父類新增this.speak函數
function Animal(name,type) {
  this.name = name || 'your name';
  this.type= type || 0;
  this.coatColor= ['white','block','yellow','brown']; //引用類型
    //函數也是引用類型
  this.speak = function () {
      console.log(this.name+' speaking .');
  }
}

//測試
console.log(pig1.speak===pig2.speak); // false

以上證實,父類的函數,在子類的實例下是不共享的。this

怎麼辦呢?,以上能夠看出原型鏈繼承構造函數繼承 這兩種繼承方式的優缺點恰好是互相矛盾的,那麼咱們有沒有辦法魚和熊掌兼得呢? 答案是確定的————組合繼承prototype

// 父類
    function Animal() {
        this.name = name || 'your name';
        this.type= type || 0;
        this.coatColor= ['white','block','yellow','brown']; //引用類型
    }
    
    // 父類函數
    Animal.prototype.speak =function () {
          console.log(this.name+' speaking .');
      }
    
    // 子類
    function Chicken(){
        Animal.call(this)             // 構造函數繼承(繼承屬性)
    }
    // 繼承
    Chicken.prototype = new Animal()  // 原型鏈繼承(繼承方法)

總結

繼承方式 核心代碼 優缺點 用法
原型鏈繼承 Dog.prototype = new Animal() 實例的引用類型共享 繼承屬性
構造函數繼承 在子類Cat)裏執行 Animal.call(this) 會獨享全部屬性,包括引用屬性(重點是函數) 繼承方法
組合繼承 利用原型鏈繼承要共享的屬性,利用構造函數繼承要獨享的屬性 實現相對完美的繼承 結合上兩位

本文中的代碼見demo coding ,若是以爲對您有用,幫加個star,萬分感謝!code

今天就寫到這,講述了3種繼承方式,其實J繼承還有不少繼承方式。其餘留在下期再見咯。感受各位的收看,歡迎提問。

相關文章
相關標籤/搜索