Skip to content

Instantly share code, notes, and snippets.

@kmdavis
Last active March 6, 2017 23:24
Show Gist options
  • Save kmdavis/4b93f5cb10f6c72209e1d7f705d46ed2 to your computer and use it in GitHub Desktop.
Save kmdavis/4b93f5cb10f6c72209e1d7f705d46ed2 to your computer and use it in GitHub Desktop.
ES6 Multiple Inheritance
function inheritObjects (parents, proxyTarget = Object.create(null)) {
const proxy = new Proxy(proxyTarget, {
defineProperty (target, name, prop) {
Object.defineProperty(target, name, prop);
return true;
},
deleteProperty (target, name) {
delete target[name];
},
get (target, name) {
if (Object.prototype.hasOwnProperty.call(target, name)) {
return target[name];
}
for (const obj of parents) {
if (name in obj) {
return obj[name];
}
}
},
getPropertyDescriptor (target, name) {
if (Object.prototype.hasOwnProperty.call(target, name)) {
return Object.getPropertyDescriptor(target, name);
}
for (const obj of parents) {
const prop = Object.getPropertyDescriptor(obj, name)
if (prop) {
return prop;
}
}
},
has (target, name) {
if (Object.prototype.hasOwnProperty.call(target, name)) {
return true;
}
for (const obj of parents) {
if (name in obj) {
return true;
}
}
return false;
},
ownKeys (target) {
const keys = Object.getOwnPropertyNames(target);
for (const obj of parents) {
for (const name of Object.getOwnPropertyNames(obj)) {
if (!~keys.indexOf(name)) {
keys.push(name);
}
}
}
return keys;
},
set (target, name, value) {
target[name] = value;
}
})
return proxy;
}
const INHERITED_PARENTS = Symbol("inheritedParents");
function inheritClasses (parents) {
function dummy () {};
dummy[INHERITED_PARENTS] = parents;
dummy.prototype = inheritObjects(parents.map(p => p.prototype));
return inheritObjects(parents, dummy);
}
function inherits (...parents) {
return inheritClasses(parents);
}
class Inheritable {
static [Symbol.hasInstance] (inst) {
const parents = [inst.constructor];
while (parents.length) {
const parent = parents.shift();
if (parent === this) {
return true;
}
if (parent[INHERITED_PARENTS]) {
parents.push(...parent[INHERITED_PARENTS]);
} else if (parent.__proto__) {
parents.push(parent.__proto__);
}
}
return false;
}
}
// ============================
class Foo extends Inheritable {
foo () { console.log("foo"); }
both () { console.log("foo wins"); }
}
class Bar extends Inheritable {
bar () { console.log("bar"); }
both () { console.log("bar wins"); }
}
class Baz extends inherits(Foo, Bar) {}
// ============================
const baz = new Baz();
baz.foo();
baz.bar();
baz.both();
console.log(baz instanceof Foo);
console.log(baz instanceof Bar);
console.log(baz instanceof Baz);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment