2
\$\begingroup\$

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 .

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 the createObject 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).
\$\endgroup\$
  • \$\begingroup\$ It might help if you could describe what universe.createClass() is trying to do and why a function passed to it has to call such a hugely long thing like this.universe.classes.Atom.prototype.fullName.call(this) in the first place. \$\endgroup\$ – jfriend00 Mar 26 '15 at 21:43
  • \$\begingroup\$ Sorry for the delay, check out the explanation @jfriend00. It should be more clear now. \$\endgroup\$ – josegomezr Mar 27 '15 at 19:57
  • \$\begingroup\$ Why would you register a class name with a framework and have to call CreateObject() 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? \$\endgroup\$ – jfriend00 Mar 27 '15 at 23:47
  • \$\begingroup\$ I need a way to declare classes modularly, each module will have an universe reference injected so they have access to createClass. The createObject call allow me to Notify the universe that a class has been instantiated. \$\endgroup\$ – josegomezr Mar 29 '15 at 17:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.