js multi-inheritance simulation

Run Settings
LanguageJavaScript
Language Version
Run Command
const mixinProps = (target, source) => { Object.getOwnPropertyNames(source).forEach(prop => { if (/^(?:constructor|isInstanceOf)$/.test(prop)) { return; } Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop)); }) }; const mroMerge = (list) => { if (!list || !list.length) { return []; } for (let items of list) { let item = items[0]; let valid = true; for (let items2 of list) { if (items2.indexOf(item) > 0) { valid = false; break; } } if (valid) { nextList = []; for (let items3 of list) { let _index = items3.indexOf(item); if (_index > -1) { items3.splice(_index, 1); } items3.length && nextList.push(items3); } return [item, ...mroMerge(nextList)]; } } throw new Error('Unable to merge MRO'); }; const c3mro = (ctor, bases) => { if (!bases || !bases.length) { return [ctor]; } let list = bases.map(b => b._meta.bases.slice()); list = list.concat([bases]); let res = mroMerge(list); return [ctor, ...res]; }; const createClass = (parents, props) => { const isMulti = parents && Array.isArray(parents); const superCls = isMulti ? parents[0] : parents; const mixins = isMulti ? parents.slice(1) : []; const Ctor = function(...args) { // TODO: call each parent's constructor if (props.constructor) { props.constructor.apply(this, args); } }; // save c3mro into _meta let bases = [superCls, ...mixins].filter(item => !!item); Ctor._meta = { bases: c3mro(Ctor, bases) }; if (superCls && typeof superCls === 'function') { Ctor.prototype = Object.create(superCls.prototype); Ctor.prototype.constructor = Ctor; } // mix into prototype according to [Method Resolution Order] if (Ctor._meta.bases.length > 1) { let providers = Ctor._meta.bases.slice(1).reverse(); providers.forEach(provider => { // TODO: prototype of superCls is already inherited by __proto__ chain (provider !== superCls) && mixinProps(Ctor.prototype, provider.prototype); }); } mixinProps(Ctor.prototype, props); Ctor.prototype.isInstanceOf = function(cls) { let bases = this.constructor._meta.bases; return bases.some(item => item === cls) || (this instanceof cls); } return Ctor; }; // ================== // for test only // ================== const O = createClass(null, {}); const X = createClass([O], {}); const Y = createClass([O], { methodY() { return 'Y'; } }); const A = createClass([X, Y], { testName() { return 'A'; } }); const B = createClass([Y], { testName() { return 'B'; } }); const C = createClass([A, B], { constructor() { this._name = 'custom C'; } }); let obj = new C(); console.log(obj.isInstanceOf(O)); // true console.log(obj.isInstanceOf(X)); // true console.log(obj.isInstanceOf(Y)); // true console.log(obj.isInstanceOf(A)); // true console.log(obj.isInstanceOf(B)); // true console.log(obj.isInstanceOf(C)); // true console.log(obj.testName()); console.log(obj.methodY());
Editor Settings
Theme
Key bindings
Full width
Lines