Introduction
I decided to jump into JavaScript ES6 and start learning the new features. I like everything except the lack of multiple inheritance support for classes. Having to chain around single classes to make multi inheritance is a pain in the ass. So in an attempt to resolve the problem, I came up with the class below.
Multi Inheritance Class
class multi
{
static inherit(..._bases)
{
class classes {
get base() { return _bases; }
constructor(..._args)
{
var index = 0;
for (let b of this.base)
{
let obj = new b(_args[index++]);
multi.copy(this, obj);
}
}
}
for (let base of _bases)
{
multi.copy(classes, base);
multi.copy(classes.prototype, base.prototype);
}
return classes;
}
static copy(_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);
}
}
}
}
How Does it Work?
In order for multi inheritance to work, I utilized a lot of the new ES6 features in combination with ES5. The class is extended by using the following code.
class person extends ages
class person extends multi.inherit(ages, genders)
Instead of passing a class to the extend, we pass a static function called inherit, which returns a class after merging properties and methods together of other named classes. Inside the inherit method, we receive a rest parameter with all class names to inherit from.
get base() { return _bases; }
This is a key feature for creating the instances of each class and copying their properties in the constructor method. We forward the parameters from the super() to the constructor.
constructor(..._args)
{
var index = 0;
for (let b of this.base)
{
let obj = new b(_args[index++]);
multi.copy(this, obj);
}
}
Below is a full working example of multiple inheritance.
Full Sample Code
class multi
{
static inherit(..._bases)
{
class classes {
get base() { return _bases; }
constructor(..._args)
{
var index = 0;
for (let b of this.base)
{
let obj = new b(_args[index++]);
multi.copy(this, obj);
}
}
}
for (let base of _bases)
{
multi.copy(classes, base);
multi.copy(classes.prototype, base.prototype);
}
return classes;
}
static copy(_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);
}
}
}
}
class ages
{
constructor(_age) { this.age = _age; }
set age(_a) { this._age = _a; }
get age() { return this._age; }
increase() { this.age++; }
}
class genders
{
constructor(_gender) { this.gender = _gender; }
set gender(_g) { this._gender = _g; }
get gender() { return this._gender; }
male() { this._gender = 'M'; }
female() { this._gender = 'F'; }
}
class person extends multi.inherit(ages, genders)
{
constructor(...args)
{
super(18, 'M');
this.name = args[0];
}
set name(_n) { this._name = _n; }
get name() { return this._name; }
}
var p = new person('Adam');
console.log(p.name, p.age, p.gender);
History
Version 0.1 - First release of script, needs perfecting.