Last active
March 2, 2016 18:47
-
-
Save ephys/3a5536aa9a21b4210737 to your computer and use it in GitHub Desktop.
ES6 class mixin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
'use strict'; | |
function mergeClass(receivingClass, givingPrototype) { | |
if (givingPrototype === Object.prototype) { | |
return; | |
} | |
// fetch inherited properties | |
const givingPrototypeProto = Object.getPrototypeOf(givingPrototype); | |
if (givingPrototype != null) { | |
mergeClass(receivingClass, givingPrototypeProto); | |
} | |
// done | |
const receivingPrototype = receivingClass.prototype; | |
for (let propertyName of Object.getOwnPropertyNames(givingPrototype)) { | |
if (propertyName === 'contructor') { | |
continue; | |
} | |
receivingPrototype[propertyName] = givingPrototype[propertyName]; | |
} | |
} | |
function merge(receivingClass, ...mixins) { | |
for (let i = 0; i < mixins.length; i++) { | |
const mixin = mixins[i]; | |
if (mixin == null) { | |
throw new Error(`Invalid mixin n° ${i}`); | |
} | |
if (typeof mixin === 'object') { | |
mergeClass(receivingClass, mixin); | |
} | |
if (typeof mixin === 'function') { | |
mergeClass(receivingClass, mixin.prototype); | |
} | |
} | |
return receivingClass; | |
} | |
// tests | |
class Animal { | |
constructor(name) { | |
this.name = name; | |
} | |
eat() { | |
console.log(`${this.name} is now eating.`); | |
} | |
die() { | |
throw new Error('you\'re a terrible person.'); | |
} | |
} | |
// supports other classes | |
class FlyMixin { | |
fly() { | |
console.log(`${this.name} is now flying.`); | |
} | |
} | |
// or plain objects | |
const WalkMixin = { | |
walk() { | |
console.log(`${this.name} is now walking.`); | |
} | |
}; | |
const Cat = merge(class extends Animal {}, WalkMixin); | |
const Bird = merge(class extends Animal {}, WalkMixin, FlyMixin); | |
let bird = new Bird('birdy'); | |
let cat = new Cat('cat... ty ?'); | |
bird.eat(); // birdy is now eating. | |
cat.eat(); // cat... ty ? is now eating. | |
bird.walk(); // birdy is now walking. | |
cat.walk(); // cat... ty ? is now walking. | |
bird.fly(); // birdy is now flying. | |
cat.fly(); // Uncaught TypeError: cat.fly is not a function | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment