Skip to content

Instantly share code, notes, and snippets.

@nanto
Created August 17, 2014 10:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nanto/38e336bfd5de86af7310 to your computer and use it in GitHub Desktop.
Save nanto/38e336bfd5de86af7310 to your computer and use it in GitHub Desktop.
Emulate 'class' of class-based object-oriented languages.
// classify -- emulate 'class' of class-based object-oriented languages.
//
// This file is in the public domain.
//
// classify(constructor, members)
// classify(constructor, superConstructor)
// classify(constructor, superConstructor, members)
//
// If you specify 'superConstructor', you can call 'callSuper' method in 'constructor'.
//
var classify = (function () {
function extend(destination, source) {
var properties = {};
var keys = Object.keys(source);
for (var i = 0; i < keys.length; i++) {
properties[keys[i]] = Object.getOwnPropertyDescriptor(source, keys[i]);
}
Object.defineProperties(destination, properties);
return destination;
}
function inherit(Sub, Super) {
// Pairs of an instance and a constructor which is being called.
var constructs = [];
function callSuper() {
var n = constructs.length;
if (n && constructs[--n][0] === this) {
var ctr = constructs[n][1] = constructs[n][1]._super.constructor;
return ctr.apply(this, arguments);
}
constructs.push([this, Super]);
try {
return Super.apply(this, arguments);
} finally {
// In a single-threaded environment, `constructs` is a LIFO stack.
constructs.pop();
}
}
Sub.prototype = Object.create(Super.prototype, {
constructor: { value: Sub },
callSuper: { value: callSuper },
});
Object.defineProperty(Sub, '_super', { value: Super.prototype });
return Sub;
}
function classify(constructor) {
var i = 1;
if (typeof arguments[i] === 'function') {
inherit(constructor, arguments[i++]);
}
for (; i < arguments.length; i++) {
extend(constructor.prototype, arguments[i]);
}
return constructor;
}
classify.extend = extend;
classify.inherit = inherit;
return classify;
})();
// Examples:
function A(arg) {
this.a = arg;
}
classify(A, {
get propA() { return this.a; },
methodA: function () { return this.a; },
});
function B(arg) {
this.callSuper(arg);
this.b = arg;
}
classify(B, A, {
get propB() { return this.b; },
methodB: function () { return this.b; },
});
function C(arg) {
this.callSuper(arg);
this.c = arg;
}
classify(C, B, {
get propC() { return this.c; },
methodC: function () { return this.c; },
});
var o = new C(42);
console.assert(o.a === 42, 'constructor A is called');
console.assert(o.b === 42, 'constructor B is called');
console.assert(o.c === 42, 'constructor C is called');
console.assert(o.propA === 42, 'properties of A are defined');
console.assert(o.propB === 42, 'properties of B are defined');
console.assert(o.propC === 42, 'properties of C are defined');
console.assert(o.methodA() === 42, 'methods of A are defined');
console.assert(o.methodB() === 42, 'methods of B are defined');
console.assert(o.methodC() === 42, 'methods of C are defined');
console.log(o);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment