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à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
后周霉,不知道是什么機制導(dǎo)致,MIx的constructor
還是為空亚皂,
此時我求助于Stack Overflow:鏈接俱箱。
根據(jù)其中解答,我總結(jié)了以下幾點:
- 首先孕讳,在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不同的一點)璃饱,正確的做法應(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就可以了)