js繼承之組合繼承(結合原型鏈繼承 和 借用構造函數繼承)


在我的前兩篇文章中,我們已經介紹了 js 中實現繼承的兩種模式:原型鏈繼承借用構造函數繼承。這兩種模式都存在各自的缺點,所以,我們考慮是否能將這二者結合到一起,從而發揮二者之長。即在繼承過程中,既可以保證每個實例都有它自己的屬性,又能做到對一些屬性和方法的復用。這樣就 perfect 了。

一、回顧借用構造函數繼承的缺點

先看我們之前在借用構造函數繼承中最后用到的代碼:

    //父類:人
    function Person () {
      this.head = '腦袋瓜子';
      this.emotion = ['喜', '怒', '哀', '樂']; //人都有喜怒哀樂
      this.eat = function () {
        console.log('吃吃喝喝');
      }
      this.sleep = function () {
        console.log('睡覺');
      }
      this.run = function () {
        console.log('快跑');
      }
    }
    //子類:學生,繼承了“人”這個類
    function Student(studentID) {
      this.studentID = studentID;
      Person.call(this);
    }
    
    //Student.prototype = new Person();

    var stu1 = new Student(1001);
    console.log(stu1.emotion); //['喜', '怒', '哀', '樂']

    stu1.emotion.push('愁');
    console.log(stu1.emotion); //["喜", "怒", "哀", "樂", "愁"]
    
    var stu2 = new Student(1002);
    console.log(stu2.emotion); //["喜", "怒", "哀", "樂"]

  

  在這段代碼中,我們通過借用構造函數繼承,保證了 stu1 和 stu2 都有各自的父類屬性副本,從而使得各自 emotion 互不影響。但同時帶來的問題是,stu1 和 stu2 都拷貝了 Person 類中的所有屬性和方法,而在 Person 類中,像 eat ( ), sleep ( ), run ( ) 這類方法應該是公用的,而不需要添加到每個實例上去,增大內存,尤其是這類方法較多的時候。

 

二、結合使用兩種繼承模式

  所以我們想到,是否能把這些方法掛載到父類的原型對象上去,實現方法復用,然后子類通過原型鏈繼承,就能調用這些方法啦?~

    //父類:人
    function Person () {
      this.head = '腦袋瓜子';
      this.emotion = ['喜', '怒', '哀', '樂']; //人都有喜怒哀樂
    }
    //將 Person 類中需共享的方法放到 prototype 中,實現復用
    Person.prototype.eat = function () { console.log('吃吃喝喝'); } Person.prototype.sleep = function () { console.log('睡覺'); } Person.prototype.run = function () { console.log('快跑'); } //子類:學生,繼承了“人”這個類
    function Student(studentID) {
      this.studentID = studentID;
      Person.call(this);
    }
    
    Student.prototype = new Person();  //此時 Student.prototype 中的 constructor 被重寫了,會導致 stu1.constructor === Person
    Student.prototype.constructor = Student;  //將 Student 原型對象的 constructor 指針重新指向 Student 本身

    var stu1 = new Student(1001);
    console.log(stu1.emotion); //['喜', '怒', '哀', '樂']

    stu1.emotion.push('愁');
    console.log(stu1.emotion); //["喜", "怒", "哀", "樂", "愁"]
    
    var stu2 = new Student(1002);
    console.log(stu2.emotion); //["喜", "怒", "哀", "樂"]

    stu1.eat(); //吃吃喝喝
    stu2.run(); //快跑
    console.log(stu1.constructor);  //Student

 

  首先,我們將 Person 類中需要復用的方法提取到 Person.prototype 中,然后設置 Student 的原型對象為 Person 類的一個實例,這樣 stu1 就能訪問到 Person 原型對象上的屬性和方法了。其次,為保證 stu1 和 stu2 擁有各自的父類屬性副本,我們在 Student 構造函數中,還是使用了 Person.call ( this ) 方法。如此,結合原型鏈繼承和借用構造函數繼承,就完美地解決了之前這二者各自表現出來的缺點。

 

如果你覺得文章解決了你的疑惑的話,還請賞我一個推薦哦~  :)

作者不才,文中若有錯誤,望請指正,避免誤人子弟。

文章內容全都參考於《JAVASCRIPT 高級程序設計》第三版)

 


免責聲明!

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



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