Created
November 1, 2011 14:08
-
-
Save DmitrySoshnikov/1330574 to your computer and use it in GitHub Desktop.
Class lib sugar for JS
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
/** | |
* 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