Scalable JavaScript Application

Make of JavaScript the language you need

Any diligent developer is constantly working on improving his or her code. There are plenty of books telling how to make your code better. However most of them use the language of class-based OOP. Reader must have enough of experience to reflect those classical design patterns on JavaScript. Thus, many and many developers give up on the language before mastering its true power. That is one of major reasons JavaScript is referred sometimes as The World's Most Misunderstood Programming Language.On the other hand, JavaScript is an incredible impressive language. I wonder if JavaScript was originally designed as a foundation on which you build your own language.

About 2 years ago I had worked out a solution which developed by now into a light-weight library which brings into JavaScript everything I miss in the language as a follower of class-based OOP:

  • classes containing as members as well as meta-information within their declaration
  • descending inheritance (abstract class -> class -> .. -> final class)
  • interface concept support
  • mixins or traits support
  • type hinting
  • entry point validators
  • extra: abstract widget class to supply derivatives with predefined behavior

And as I said that is a light-weight library, about 3K for all those features. Looks promising, isn't it? I hope so, since I'm going to dive into details of how it is implemented and how it feels on a use.


Factory

I'm used to expect from a class an image of what the objects derived from it will look like. I want the class declaration to comprise private and public members and point at its generalization, aggregation and interfaces. Classical prototypal style does not really suit these requirements:

var ConstructorFunc = function () {
    var _privateMember = "private member";
}
ConstructorFunc.prototype.publicMember = "public member";
ConstructorFunc.prototype.privilegedMethod = function () {
    return _privateMember;
};

But if we tune it into a module, that will look pretty much like what I asked:

var ConcreteClass = function () {
    // Constructor's job
    var _privateMember = "private member";
    return {
        __extends__: AbstractClass,
        __implements__: [Countable, Traversable],
        __mixin__: [Trait]
        publicMember : "public member",
        privilegedMethod : function () {
            return _privateMember;
        }
    }
}

However as soon as you will try to extend this/by this kind of object you have a trouble (Details in Prototypal Inheritance in JavaScript for Modules). In order to fix it, we need a control over object creation. Thus, a factory will serve.

(function( global ) {
    "use strict";
 
/**
* Create instance of a given type and pass arguments to its constructor
*
* @see xObject.create
* @param {function} constr - class object || {object} proto
* @param {array} args - array of arguments
* @return {object} instance
*/
 var createInstance = function( constr, args, props ) {
          var instance,
              members = ( typeof constr === "function" ? constr.apply( constr.prototype, args || [] ) : constr ),
              Fn = function () {};

          // mix-in properties if any given
          xObject.mixin( members || {}, props || {} );

          // Inherit from a super type if any specified in __extends__ property
          if ( members.hasOwnProperty( "__extends__" ) && members.__extends__ ) {
              constr.prototype = createInstance( members.__extends__, args );
          }
          // Copy given type prototype linking to a new constructor
          Fn.prototype = constr.prototype || {};
          // Mix-in members of given type to the new constructor's prototype
          xObject.mixin( Fn.prototype, members );
          instance = new Fn();
          // Call constructor function if any specified in __constructor__ property

          members.hasOwnProperty("__constructor__") &apm;&
              members.__constructor__.apply( instance, args || [] );
          return instance;
        };

/**
* Core factory method implementing controlled instation
* xObject.create( constructor || proto [, argumentsArray, propertiesObject ])
*
* @param {function} constructor || {object} prototype
* [@param {array} constructor arguments array]
* [@param {object} properties object to mix-in]
* @return (object) instance
*/
    xObject.create = function (constr, args, props) {
    // Plus few lines to validate input, and infer arguments by given type. E.g. if second parameter is an object that goes to props and means args = [] 
        return createInstance( constr, args, props );
    };

    global.xObject = xObject;
    return xObject;

})( this );

Since we decided that all the objects are being created through the factory, we are really in control of object creation. So we can make the newly created object to inherit from the class specified __extends__ property. The same way we can, for example, aggregate objects enlisted in __mixin__ property. So, we can do many yummy things through the factory and it's unclear which functionally we would like in inject into factory in future. But using hooks it would not be a problem. Thus, we declare a factory hooks collection, accessible for factory plugins. For that we have to change the factory method a bit:

...
xObject.create = function (constr, args, props) {
        var instance = createInstance( constr, args, props );
        xObject.hooks.invokeAll( instance, arguments );
        return instance;
    };

Usage example:

var o = xObject.create( ConcreteModule );
console.log( o instanceof ConcreteModule ); // true
console.log( o instanceof AbstractModule ); // true
// o comprise as ConcreteModule public members as well as AbstractModule public members

Widgets

JavaScript is often used on DOM-tree, dealing with reusable page representation components (widgets). The most sophisticated pattern I have found so far is YUI Widgets. I especially liked the idea where any object inheriting from WidgetAbstract gets widget behavior such as auto-calling init, renderUi, syncUi, bindUi methods and populating an object with node references based on HTML_PARSER instructions. As you see, that is a part which is easy to implement when having our magic factory. xObject.BaseAbstract constructor assigns a hook which makes object to run init, renderUi, bindUi and syncUi methods right after its creation. xObject.WidgetAbstract constructor adds another hook, preceding the first one. That makes the object to populate node property with node references based on the selectors given in HTML_PARSER (in the context of this.boundingBox).

Following example illustrates handling widgets with xObject (for clearness here used jQuery API)

(function( $, xObject ) {
    "use strict";
    // Application scope
    var App = (function() {
        return {
            init : function() {;
                // Invoke the first instance of Intro
                xObject.create( App.Intro, { boundingBox: $('div.intro') } );
            }
        }
    }());
    //  Widget
    App.Intro = function( settings ) {
        // event handlers
        _handler = {
            onclick : function(e) {
                // e.data is 'this' context of the module
                e.data.node.boundingBox.attr( 'data-pattern', $( this ).data( 'id' ) );
            }
        };
        return {
            __extends__ : xObject.WidgetAbstract,
            HTML_PARSER : {
                toolbar : 'div.toolbar'
            },
            bindUi : function() {
                this.node.toolbar.find( 'li' ).bind( 'click.intro', this, _handler.onclick );
            }
        };
    };
    // Document is ready
    $(document).bind( 'ready.app', App.init );

})( jQuery, xObject );

If you don't use jQuery, just specify in code, before xObject script defined, your own querySelector function:

xObject.querySelectorFn = function(query, context)  {
    context = context || document;
    return context.querySelector(query);
}

Mixins

Mixing plugin assigns a factory hook, which, respectively, mix members of static object given by __mixin__ property into newly created object.

MixinA = {
    propertyA: "propertyA"
};
MixinB = {
    propertyB: "propertyB"
};
Silo = function() {
    return {
        __mixin__: [ MixinA, MixinB ],
        ownPropery: "Own property"
    }
};

var o = xObject.create( Silo );
console.log( o.ownPropery !== undefined ); // true
console.log( o.propertyA !== undefined ); // true
console.log( o.propertyB !== undefined ); // true

Interfaces

Program to an 'interface', not an 'implementation' (The Gang of Four)

By interface xObject expects an abstract object that is used to specify an interface (mandatory members and arguments) that classes must implement:

ConcreteInterface = {
       methodName : ["string", aClass]
};

Interface plugin assigns a factory hook, which checks if the newly born object meets the requirements of the interfaces enlisted in __implements__ property. It's clear how to check if the object contains members defined by an interface. But how to check member arguments? What I really love in JavaScript, the language allows us to override methods dynamically and that brings an incredible flexibility. We can wrap our members defined by an interface with cross-cutting functionality. In this case it is a check for arguments on the entry point. The plugins expects that interface static object comprises members names where each one points at the array of type hints. Just like in PHP. This way we declare how many and of which types arguments allowed for the members of the object implementing this interface.

InjectedDependency = function() {
    return {
    };
};

ConcreteInterface = {
    requeriedMethod : ["string", InjectedDependency]
};

StrictModule = function() {
    return {
        __implements__: ConcreteInterface,
        requeriedMethod : function() {
        }
    }
};

var dependency = xObject.create( InjectedDependency ),
      module = xObject.create( StrictModule );

console.log( dependency instanceof InjectedDependency ); // true
module.requeriedMethod("a string", dependency); // OK
module.requeriedMethod(555, dependency); // throws a TypeError exception
module.requeriedMethod("a string", {}); // throws a TypeError exception

DbC

Design by Contract approach provides another and more sophisticated solution of defining requirements for the objects of a type. By a contract we can define not only member the object must have and argument type hints to match on the entry point, but a type hint on exit point and validators for arguments values:

Contract = {
         methodName : {
              onEntry: [ "number", aClass ], // type hints
              validators: [function(arg){
                  return arg > 10;
              }],
              onExit: "string"
          }
     };

BbC plugin assigns a hook pretty much like Interface plugin does. Unless when wrapping a member it adds a check on exit point too and runs validators over the member arguments. The usage may look like:

ConcreteContract = {
    aMethod : {
        onEntry: [ "number"],
        validators: [function(arg){
            return arg > 10;
        }],
        onExit: "string"
    }
};
EmployedModule = function() {
    return {
        __contract__: ConcreteContract,
        aMethod : function() {
            return "a string";
        }
    }
};
var module = xObject.create( EmployedModule );
module.aMethod(50); // OK
module.aMethod(1); // validator fails, RangeError exception is thrown

Conclusion

xObject is not a panacea of any kind, but it serves me well for years and so it may be useful for you. Besides, you can exploit the idea of a hookable factory to produce your own plugins fitting your peculiar requirements.

You can find xObject library source code, test and examples at the library project page