I'm making an experiment on JS, trying to build a framework for OOP. It's called Universe.
The main purpose is to emulate a mini-universe, where classes are "created" with a defined behavior (prototype) and objects are created from those classes to provide data.
So far I managed to make inheritance work (although the instanceof
operator doesn't work), but my inheritance looks horrible. I've like 6 hours trying to make it pretty, but I always get stuck on a huge line like
this.universe.classes.<ClassName>.prototype.fullName.call(this)
Excerpt from index.js
// trimmed for brevity
var MoleculeClass = universe.createClass('Molecule', {
fullName: function () {
return this.universe.classes.Atom.prototype.fullName.call(this) + " -- new molecule name with atoms -> " + this.get('numberOfAtoms') + "\n";
}
}, 'Atom');
How can I make this "parent call" look more natural? More like this.parent.fullName
or something like that.
When I tried passing parent as a reference to parent class it worked nice on 1-level inheritance, on a 2-level (grandchild class) the middle (child class) throws me a max call stack size exceeded error.
The BigBang.js library
is.js and utils.js are just convenient shortcuts; they may be changed for some library like lodash.js.
var is = require('./is.js');
var utils = require('./utils.js');
module.exports = (function () {
var Containers = {};
var GProto = {
get: function(k){
return Containers[this.__objectId__][k];
},
set: function(k, v){
Containers[this.__objectId__][k] = v;
},
init: function(ctorArgs){
Containers[this.__objectId__] = utils.extend({}, Containers[this.__objectId__], ctorArgs);
},
id: function(){
return this.__objectId__;
}
};
function Bigbang (config) {
this.classes = {};
this.inheritances = {};
this.instances = {};
this.handlers = {};
};
Bigbang.prototype = utils.extend({}, Bigbang.prototype, {
createClass: function (className, newProto, inheritsFrom) {
inheritsFrom = inheritsFrom || null;
var newClass = function GClass(){};
var parentClass = this.findClass(inheritsFrom);
newClass.prototype = utils.extend({}, Object.create(parentClass ? parentClass.prototype : GProto), {
__class__: className
}, newProto);
newClass.prototype.constructor = newClass;
this.inheritances[className] = inheritsFrom;
this.classes[className] = newClass;
return this.createObject.bind(this, className);
},
findClass: function (className) {
return utils.have(this.classes, className) ? this.classes[className] : undefined;
},
createObject: function (className, ctorArgs) {
var classToBe = this.findClass(className);
var uid = utils.uniqueId('object_');
var instance = new classToBe();
instance.__objectId__ = uid;
instance.universe = this;
Containers[uid] = {};
instance.init(ctorArgs);
return instance;
}
});
return Bigbang;
})();
Little Explanation
CreateClass
- Method creates a 'class' under the universe.
- It'll apply inheritance and store it in
classes
for further use from thecreateObject
method.
CreateObject
- Creates an instance of a 'created' class.
- Attach an
objectID
. - Link the
universe
where it's created. - Reserve a space in
Containers
to store its data. - Call init function (constructor).
universe.createClass()
is trying to do and why a function passed to it has to call such a hugely long thing likethis.universe.classes.Atom.prototype.fullName.call(this)
in the first place. – jfriend00 Mar 26 at 21:43CreateObject()
with that name rather than just define a constructor function and call the constructor function to create a new object. I don't understand what you're trying to accomplish in this framework that is advantageous over a normal constructor function and perhaps a single utility function for inheriting from something else. And with ES6 on the way with an explicit syntax for new types of objects and transpilers already supporting ES6, why are you inventing something new and what are its advantages? – jfriend00 Mar 27 at 23:47universe
reference injected so they have access to createClass. The createObject call allow me to Notify the universe that a class has been instantiated. – josegomezr Mar 29 at 17:01