Javascript Application Design Patterns, By Example

Sam Deering
Tweet

Javascript development is dominated by libraries libraries like Backbone, Spine, and of course jQuery (surprise!). However, it isn’t an issue of what library to use but rather how to use it.

Understanding how some frameworks provide scaffolding and architecture to a seemingly non-deterministic glob of javascript can be a key component in our arsenal of javascript tricks. Having this knowledge essentially unlocks the last door to creating truly great and immersive web applications by letting the developer logically separate concerns and dependencies.

In this article, we will walk through some basic javascript patterns:

  • IIFE Modules
  • Dojo Modules
  • jQuery Modules
  • AMD Modules
  • CommonJS Modules
  • Facade Patterns
  • Mediator Modules

Module patterns — Immediately Invoked Expression Functions (IIEF) use execution context to create privacy.

var module = (function(){
    /**
     * private variables are declared only inside the module
     */
    var basket = [];

    /**
     * public variables are declared in the returned object
     */
    return {
        add: function(value){ ... },
        count: function() { ... }
    };
}());

module.add('a');
module.add('b');
module.add('c');

var total = module.count();

Module Pattern – Dojo

/**
 * traditional method
 */
var store = window.store || {};
store.basket = store.basket || {};

/**
 * dojo method
 */
dojo.setObject("store.basket.object", function(){
    var basket = [];
    function privateFunc(){ ... }
    return {
        add: function(value){ ... },
        count: function(){ ... }
    }
});

Module Pattern – jQuery

function library(module) {
    $(function(){
        if (module.init) {
            module.init();
        }
    });
    return module;
}

var myLibrary = library(
    function(){
        return {
            init: function() {
                /*implementation*/
            }
        };
    }()
);

Better – Asynchronous Module Definition, or AMD

/**
 * AMD: define()
 * define a signature with define(id /*optional*/, [dependencies], /*factory module instantiation of fn*/);
 */

define(
    /*module id*/
    'myModule',

    /*dependencies*/
    ['foo', 'bar;, 'baz'],

    /*definition for the module export*/
    function(foo, bar, baz){

        /*module object*/
        var module = {};

        /*module methods go here*/
        module.hello = foo.getSomething();
        module.goodbye = bar.getSomething();

        /*return the defined module object*/
        return module;
    }
);

/**
 * AMD: require()
 * load top-level code for JS files or inside modules for dynamically fetching dependencies
 */

/* top-level: the module exports (one, two) are passed as function arguments ot the object */
require(['one', 'two'], function(one, two){
    ...
});

/*inside: the complete example*/
define('three', ['one', 'two'], function(one, two){
    /**
     * require('string') can be used inside the function to get the module export
     * of a module that has already been fetched and evaluated
     */

    var temp = require('one');

    /*this will fail*/
    var four = require('four');

    /* return a value to define the module export */
    return function(){ ... };
});

Best: CommonJS – Widely adopted server-side format

/**
 * basically contains two parts: an exports object that contains the objects a module wishes to expose
 * and a require function that modules can use to import the exports of other modules
 */

/* here we achieve compatibility with AMD and CommonJS using some boilerplate around the CommonJS module format*/
(function(define){
    define(function(require,exports){
         /*module contents*/
         var dep1 = require("foo");
         var dep2 = require("bar");
         exports.hello = function(){...};
         exports.world = function(){...};
    });
})( typeof define=="function" ? define : function(factory){ factory(require, exports) });

** Harmonious revelations: ES Harmony, the the successor to ECMAScript 5

/**
 * 1. static scoping
 * 2. simple
 * 3. reusable modules
 */

// Basic module
module SafeWidget {
    import alert from Widget;
    var _private ="someValue";

    // exports
    export var document = {
        write: function(txt) {
            alert('Out of luck, buck');
        },
        ...
    };
}

// Remote module
module JSONTest from 'http://json.org/modules/json2.js';

Alternative patterns to modules

Modules are regularly used in MVC applications..but there are other patterns that can make building large apps easier too.Remember that jQuery generally plays a smaller role in larger-apps than most people might think. The 2nd.MD calendar and booking code, and the chat portal, could easily operate without jQuery.

Facade – high level interfaces to large bodies of code that hide MOST of the unerlying complexity

“When you put up a facade, you’re usually creating an outward appearance which conceals a different reality. Think of it as simplifying the API presented to other developers”

Essential Javascript Design Patterns

  1. Simplifies usage through a limited, simpler API
  2. Hides the inner-workings of the library, allows implementation to be less important
  3. Lets you be more creative behind the scenes
  4. Has many functional behaviors for application security
var module = (function() {
    var _private = {
        i:5,
        get : function() {
            console.log('current value:' + this.i);
        },
        set : function( val ) {
            this.i = val;
        },
        run : function() {
            console.log('running');
        },
        jump: function(){
            console.log('jumping');
        }
    };

    /**
     * this part includes code imported above and provides an API to the returning module
     */
    return {
        facade : function( args ) {
            _private.set(args.val);
            _private.get();
            if ( args.run ) {
                _private.run();
            }
        }
    };
}());

module.facade({run: true, val:10}); //outputs current value: 10, running

Mediator – Promotes loose coupling by establishing interfaces for events that modules can subscribe to:

  1. Allows modules to broadcast or listen for notifications without worrying about the system or tedious callback chains.
  2. Notifications can be handled asynchronously by any number of modules at a single time.
  3. Much easier to add or remove features at any time due to the loosely coupled nature of the code.
var mediator = (function(){
    var subscribe = function(channel, fn){
        if (!mediator.channels[channel])mediator.channels[channel] = [];
        mediator.channels[channel].push({ context: this, callback:fn });
        return this;
    },
    publish = function(channel){
        if (!mediator.channels[channel]) return false;
        var args = Array.prototype.slice.call(arguments, 1);
        for (var i = 0, l = mediator.channels[channel].length; i<l; i++) {
            var subscription = mediator.channels[channel][i];
            subscription.callback.apply(subscription.context,args);
        }
        return this;
    };
    return {
        channels: {},
        publish: publish,
        subscribe: subscribe,
        installTo: function(obj){
            obj.subscribe = subscribe;
            obj.publish = publish;
        }
    };
}());

That is all for now! Remember that how you organize your code and architect your application can really simplify complex programs to an almost natural instinct. Hone your skills on these approaches and you will master techniques needed to really grow as a developer!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • bestrag

    Love your post. Angular should be included

    • http://mkeas.org/ Matthew Keas

      Angular almost deserves it’s own post ;)

      • gmilby

        let’s not get carried away :-D

  • Vasco

    great post!!

  • andrewvijay

    Bro, can u pls be more specific on what this post is about? Is it server side scripting? What is that “module” that you have mentioned. Can you explain clearly what you meant!

    • http://mkeas.org/ Matthew Keas

      It is intended to be client side, but since it is javascript, can be used server side as well.

      Modules are alternative methods to create closures in javascript.

      • andrewvijay

        thanks man. cheers :)

  • http://dewmap.com/ Brett Coffin

    Thanks mate, very interesting read… I suppose a mention of the “event bus” pattern would be a good addition to the application patterns as-well

  • Pingback: Javascript Application Design Patterns, By Example » PHP Script Blog

  • gmilby

    this was useful – nice to see diff methods/approaches side by side. Thanks Sam!

    • http://mkeas.org/ Matthew Keas

      :)