JavaScript ES6 class多重繼承實踐與總結(jié)

ES6中,class原生是不支持多重繼承的,根據(jù)阮一峰ES6參考資料中的方法,通過以下方式即可實現(xiàn)class繼承多個類:

function mix(...mixins) {
  class Mix {}

  for (let mixin of mixins) {
    copyProperties(Mix, mixin);
    copyProperties(Mix.prototype, mixin.prototype);
  }

  return Mix;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if ( key !== "constructor"&& key !== "prototype"&& key !== "name") {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
}

根據(jù)實踐,這樣做有一個很大的問題,文中沒有提到,參考MDN后,發(fā)現(xiàn)MDN對于此處也沒有詳細(xì)的解答。
請看以下代碼:

 class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    introduce() {
        return `My name is ${this.name}. I am ${this.age} years old.`;
    }
};
//已經(jīng)引入了node的EventEmitter類
//現(xiàn)在通過Person和EventEmitter這兩個類,創(chuàng)建Mix類。
let Mix = mix(Person,EventEmitter);

//創(chuàng)建一個新類Teacher,繼承Mix類(理想狀況下是繼承了Person,EventEmitter這兩個類,并且能夠調(diào)用父類的構(gòu)造器)
class Teacher extends Mix {
    constructor(name,id){
        super(name,id);//此處出現(xiàn)問題,父類的構(gòu)造器是空的
    }
}
var teacher1 = Teacher("tom",21);

理想狀況下,teacher1.name == 'tom'還有teacher1.age = 21,并且teacher1還繼承了Person和Eventemitter的方法,然而實際結(jié)果是teacher1.name 和 teacher1.age都是undefined,打斷點(diǎn)調(diào)試后,發(fā)現(xiàn)問題所在,constructor在mix函數(shù)中并沒有被拷貝,因為混合多個類的時候,mix函數(shù)并不知道應(yīng)該以哪個父類的constructor作為子類的constructor,所以在copyProperties函數(shù)中,跳過了這個屬性的拷貝:

if ( key !== "constructor"&& key !== "prototype"&& key !== "name") {
let desc = Object.getOwnPropertyDescriptor(source, key);
Object.defineProperty(target, key, desc);
}

更改copyProperties函數(shù)使混合后的Mix類constructor為Person的constructor后,不知道是什么機(jī)制導(dǎo)致,MIx的constructor還是為空,
此時我求助于Stack Overflow:鏈接。
根據(jù)其中解答,我總結(jié)了以下幾點(diǎn):

  • 首先,在JavaScript實現(xiàn)多重繼承的時候,考慮是否程序設(shè)計上的不合理(最后發(fā)現(xiàn)確實是有別的途徑不通過多重繼承實現(xiàn)同樣功能)
  • 在ES5中,子類多重繼承父類,調(diào)用父類的構(gòu)造函數(shù),可以用以下方法:
function Foo(...args) {
   let _this = this;
   _this = Bar.apply(_this, args);
   _this = Baz.apply(_this, args);
   return _this;
}
  • 在ES6中,以上做法不可行:

This won't work if Bar or Baz is ES6 class because it contains a mechanism that prevents it from being called without new. In this case they should be instantiated:

  • 此處是ES6類的寫法與ES5不同的一點(diǎn)),正確的做法應(yīng)該是:
 constructor(...args) {
   super(...args)

   EventEmitter.call(this);//因為EventEmitter并不是ES6構(gòu)造的,可以當(dāng)做普通函數(shù)調(diào)用
   // or
   // EventEmitter.init.call(this);
}
copyProperties(Foo.prototype, EventEmitter.prototype);

結(jié)合本題

class Teacher extends Person{
    constructor(name,age,clazzes){
         super(name,age);
         EventEmitter.call(this);
         \\...
}

問題解決

(最后發(fā)現(xiàn)并不需要多重繼承,直接讓Class(班級)繼承EventEmitter就可以了)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • class的基本用法 概述 JavaScript語言的傳統(tǒng)方法是通過構(gòu)造函數(shù),定義并生成新對象。下面是一個例子: ...
    呼呼哥閱讀 4,203評論 3 11
  • 本文先對es6發(fā)布之前javascript各種繼承實現(xiàn)方式進(jìn)行深入的分析比較,然后再介紹es6中對類繼承的支持以及...
    lazydu閱讀 16,825評論 7 44
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,697評論 18 399
  • 強(qiáng)大的for-of循環(huán) ES6不會破壞你已經(jīng)寫好的JS代碼。目前看來,成千上萬的Web網(wǎng)站依賴for-in循環(huán),其...
    Awe閱讀 7,586評論 2 7
  • 早上把昨天閱讀的"損失規(guī)避"重新復(fù)讀了一遍,之后把第五節(jié)"價格錨點(diǎn)"聽一遍讀一遍,這是算是粗略地把劉潤老師的第一周...
    思維峰哥閱讀 299評論 0 0

友情鏈接更多精彩內(nèi)容