Skip to content

Instantly share code, notes, and snippets.

@DmitrySoshnikov
Created November 1, 2011 14:08
Show Gist options
  • Save DmitrySoshnikov/1330574 to your computer and use it in GitHub Desktop.
Save DmitrySoshnikov/1330574 to your computer and use it in GitHub Desktop.
Class lib sugar for JS
/**
* class.js
* @author Dmitry A. Soshnikov
*/
function Class(params) {
/**
* Constructor function
* If not specified, use default
* constructor with calling parent one
*/
var Class = params.constructor || function Class() {
return this.class.super.apply(this, arguments);
};
delete params.constructor;
/**
* Parent class
*/
var Parent = params.extends;
delete params.extends;
/**
* Provide inheritance if parent
* class is specified
*/
if (Parent) {
Class.prototype = Object.create(Parent.prototype, {
__parentProto__: {
value: Parent.prototype,
configurable: true,
writable: true
}
});
Object.defineProperty(Class, "super", {
value: Parent
});
Object.defineProperty(Class.prototype, "constructor", {
value: Class
});
}
if (!params.constructor) {
params.constructor = Class.emptyFn;
}
Object.defineProperty(Class.prototype, "class", {
value: Class
});
/**
* Place methods on prototype
*/
for (var method in params) if (params.hasOwnProperty(method)) {
// define the method on the prototype
Object.defineProperty(Class.prototype, method, {
value: params[method],
writable: true,
configurable: true
});
}
return Class;
}
Object.defineProperty(Object.prototype, "super", {
value: function (method) {
let proto = Object.getPrototypeOf(this);
// we should use exactly this link and not
// proto.__proto__ i.e. Object.getPrototypeOf(proto)
// since in other case we can go away to i-looping
let parentProto = proto.__parentProto__;
// remove "__parentProto__" property from
// our prototype to avoid i-looping; at 3rd and
// later levels the property will be found just deeper
delete proto.__parentProto__;
// call the parent method
var result = parentProto[method].apply(this, [].slice.call(arguments, 1));
// and restore "__parentProto__" back
Object.defineProperty(proto, "__parentProto__", {
value: parentProto,
writable: true,
configurable: true
});
return result;
}
});
// usage level
let Point = Class({
constructor: function (x, y) {
console.log('Initializing point "x" and "y":', x, y);
this.x = x;
this.y = y;
},
move: function (x, y) {
this.x = x;
this.y = y;
console.log('Moving to:', x, y);
}
});
let Point3D = Class({
extends: Point,
constructor: function (x, y, z) {
this.super('constructor', x, y);
console.log('Initializing 3D point "z"', z);
this.z = z;
},
move: function (x, y, z) {
this.super('move', x, y);
this.z = z;
console.log('3D Moving to "z":', z);
}
});
let Point4D = Class({
extends: Point3D,
constructor: function (x, y, z, time) {
this.super('constructor', x, y, z);
console.log('Initializing 4D point "time"', time);
this.move(x, y, z, time)
},
move: function (x, y, z, time) {
this.super('move', x, y, z);
this.time = time;
console.log('4D Moving to "time":', time);
}
});
let p = new Point4D(10, 20, 30, 3035);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment