JavaScript Module Design Pattern

Moving beyond adding simple JavaScript enhancements to your website to developing full-blown client-side applications is going to require organization. In this article, we’ll take a look at JavaScript Module Design Patterns and how to use them in your development.

I’m a huge fan of the JavaScript Module Design Pattern so thought it would be worthwhile for other developers to explain some use cases, the differences and why they’re important. The Module Pattern is what we’d call a “design pattern” and it’s extremely useful for a vast amount of reasons. The biggest reason I’m a fan — it makes scoping a breeze and doesn’t overcomplicate program design.

Great design is a product of care and attention applied to areas that matter, resulting in a useful, understandable, and hopefully beautiful user interface. But don’t be fooled into thinking that design is left only for designers.

Anthony Colangelo

The JavaScript Module Design Pattern also keeps things very simple, easy-to-read, use and uses Objects in a very nice way. Even better, it won’t bloat your code with repetitive this and prototype declarations.

Why use JavaScript design patterns?

  1. Architecture—The layout of your code. It’s like the foundation and skeleton of a house. It’s one of the most important aspects when building scripts. It should define rules that govern how components like models, views, and controllers interact with each other.
  2. Maintainability—Ensure your code can be easily improved and extended. In my opinion this is the second most important aspect when building JS applications. Don’t build your application so it’s locked down from improvement. Make sure you can teach your old dog new tricks.
  3. Reusability—Like with most programming, reusability is another important aspect when building your application. It’ll save you time and make maintaining it make easier.

When coding JavaScript, it’s pretty easy to get messy quick. Since it’s a loose language, it’s easy to get carried away adding bits and pieces here and there without it killing your script. That’s why architecture is one of the most important aspects when coding. Establish a framework and stick to it. It’ll provide constraints to your code to help ensure consistency throughout.


Creating a JavaScript Module

To understand what a Module can give you, you’ll need to understand what the following function concept does:

(function () {
  // code
})();

It declares a function, which then calls itself immediately. These are also known as Immediately-Invoked-Function-Expressions, in which the function creates new scope and creates “privacy”. JavaScript doesn’t have privacy, but creating new scope emulates this when we wrap all our function logic inside them. The idea then is to return only the parts we need, leaving the other code out of the global scope.

After creating new scope, we need to namespace our code so that we can access any methods we return. Let’s create a namespace for our anonymous Module.

var Module = (function () {
  // code
})();

We then have Module declared in the global scope, which means we can call it wherever we like, and even pass it into another Module.


Private methods

You’ll see and hear a lot about private methods in JavaScript. But Javascript doesn’t strictly have private methods, but we can create a working equivalent.

What are private methods you might be asking? Private methods are anything you don’t want users/devs/hackers to be able to see/call outside the scope they’re in. We might be making server calls and posting sensitive data, we don’t want to expose those functions publicly, they could post anything back then and take advantage of our code. So we can create closure and be more sensible (as best as we can with JavaScript) at protecting our code. It’s not all about protection however, there are also naming conflicts. I bet when you first started out writing jQuery/JavaScript, that you dumped all your code in one file and it was just function, function, function. Little did you know these were all global, and you probably suffered the consequence at some point. If so, you’ll learn why, and what to do to change it.

So let’s use our newly created Module scope to make our methods inaccessible outside of that scope. For beginners to the Module Pattern, this example will help understand how a private method would be defined:

var Module = (function () {
  
  var privateMethod = function () {
    // do something
  };

})();

The above example declares our function privateMethod, which is locally declared inside the new scope. If we were to attempt calling it anywhere outside of our module, we’ll get an error thrown and our JavaScript program will break! We don’t want anyone to be able to call our methods, especially ones that might manipulate data and go back and forth to a server.


Understanding “return”

Typical Modules will use return and return an Object to the Module, to which the methods bound to the Object will be accessible from the Module’s namespace.

A real light example of returning an Object with a function as a property:

var Module = (function () {
  
  return {
    publicMethod: function () {
      // code
    }
  };

})();

As we’re returning an Object Literal, we can call them exactly like Object Literals:

Module.publicMethod();

For those who haven’t used the Object Literal syntax before, a standard Object Literal could look something like this:

var myObjLiteral = {
  defaults: { name: 'Todd' },
  someMethod: function () {
    console.log(this.defaults);
  }
};

// console.log: Object { name: 'Todd' }
myObjLiteral.someMethod();

But the issue with Object Literals is the pattern can be abused. Methods intended to be “private” will be accessible by users because they are part of the Object. This is where the Module comes in to save us, by allowing us to define all our “private” stuff locally and only return “the good parts”.

Let’s look at a more Object Literal syntax, and a perfectly good Module Pattern and the return keyword’s role. Usually a Module will return an Object, but how that Object is defined and constructed is totally up to you. Depending on the project and the role/setup of the code, I may use one of a few syntaxes.

Anonymous Object Literal return

One of the easiest patterns is the same as we’ve declared above, the Object has no name declared locally, we just return an Object and that’s it:

var Module = (function () {

  var privateMethod = function () {};
  
  return {
    publicMethodOne: function () {
      // I can call `privateMethod()` you know...
    },
    publicMethodTwo: function () {

    },
    publicMethodThree: function () {

    }
  };

})();

Augmenting Modules

So far we’ve created a nice Module, and returned an Object. But what if we wanted to extend our Module, and include another smaller Module, which extends our original Module?

Let’s assume the following code:

var Module = (function () {

  var privateMethod = function () {
    // private
  };

  var someMethod = function () {
    // public
  };

  var anotherMethod = function () {
    // public
  };
  
  return {
    someMethod: someMethod,
    anotherMethod: anotherMethod
  };

})();

Let’s imagine it’s part of our application, but by design we’ve decided to not include something into the core of our application, so we could include it as a standalone Module, creating an extension.

So far our Object for Module would look like:

Object {someMethod: function, anotherMethod: function}

But what if I want to add our Module extension, so it ends up with another public method, maybe like this:

Object {someMethod: function, anotherMethod: function, extension: function}

A third method is now available, but how do we manage it? Let’s create an aptly named ModuleTwo, and pass in our Module namespace, which gives us access to our Object to extend:

var ModuleTwo = (function (Module) {
    
    // access to `Module`
    
})(Module);

We could then create another method inside this module, have all the benefits of private scoping/functionality and then return our extension method. My pseudo code could look like this:

var ModuleTwo = (function (Module) {
    
    Module.extension = function () {
        // another method!
    };
    
    return Module;
    
})(Module || {});

Module gets passed into ModuleTwo, an extension method is added and then returned again. Our Object is getting thrown about, but that’s the flexibility of JavaScript.

I can then see (through something like Chrome’s Dev Tools) that my initial Module now has a third property:

// Object {someMethod: function, anotherMethod: function, extension: function}
console.log(Module);

Another hint here, you’ll notice I’ve passed in Module || {} into my second ModuleTwo, this is incase Module is undefined – we don’t want to cause errors now do we. What this does is instantiate a new Object, and bind our extension method to it, and return it.


Private Naming Conventions

I personally love the Revealing Module Pattern, and as such, I have many functions dotting around my code that visually are all declared the same, and look the same when I’m scanning around. I sometimes create a locally scoped Object, but sometimes don’t. When I don’t, how can I distinguish between private variables/methods? The _ character! You’ve probably seen this dotted around the web, and now you know why we do it:

var Module = (function () {

  var _privateMethod = function () {
    // private stuff
  };

  var publicMethod = function () {
    _privateMethod();
  };
  
  return {
    publicMethod: publicMethod
  };

})();

jQuery Plugin Module Design Pattern

I’m a big fan of jQuery and one of the main reasons why, are the plugins. jQuery plugins make it easy to build reusable, complex applications, and allows developers to easily access those applications without a lot of research on how to set it up. The implementation of the code will be consistent with the rest of jQuery-based projects which is good for aesthetic reasons, but more importantly, developers can predict how to interact with it. It’s just another way to build a better developer interface.

Before building any jQuery plugin, it’s important to ensure the plugin doesn’t conflict with other JavaScript libraries using the $ notation. An easy thing to do with just a few lines of code:

;(function($, window, document) {
  // jQuery plugin code here
})(jQuery, window, document);

The semi-colon before the function isn’t a typo. It’s a safety net against concatenated scripts and/or other plugins that haven’t been closed properly. window and document are passed as local variables rather than globals, because it (slighty) quickens the resolution process and can be more efficiently minified (especially when both are regularly referenced in your plugin).

Next, we’ll set up our plugin by simply dropping our previously built module code inside. A plugin is just a method defined on the jQuery ($) object.

;(function($, window, document) {
  $.realTimeStocks = function() {
    var rts = {
      getData: function() {
        ...
      },
      updateSymbol: function() {
        ...
        this.getData();
      }
    };
  };
})(jQuery, window, document);

With the code above, it’s as simple to call the plugin:

var rts = $.realTimeStocks();

A (jQuery) plugin is just a method defined on the jQuery ($) object.

jQuery Plugin Options

Options are what make jQuery plugins truly reusable, because they allow for customizations for each implementation. No one project is built the same and will require customizations to suit the developer’s needs. Customizable options help ensure that developers can do that.

Also, be sure to provide default values for your options so your code is clean and won’t break should an option be required, but not set. With jQuery, it’s easy to do this with the $.extend() method.

;(function($, window, document) {
  $.realTimeStocks = function(options) {
    var rts = {
      options: $.extend({
        'updateDuration': 3000,
        'postURL': 'stockMarketAPI.php'
      }, options),
      getData: function() {
        ...
      },
      updateSymbol: function() {
        ...
        this.getData();
      }
    };
  };
})(jQuery, window, document);

The first argument of $.extend(), defines an object with all the available options and their default values. The second argument, passes through the passed-in options. This will effectively merge the two objects, overriding the defaults with any passed-in options.

An added benefit to providing default options is they almost become self-documenting. Developers can easily look at the code and see what options are available. Exposing as many options as possible will allow for more customization and help the flexibility of the plugin and future implementations.

jQuery Plugin API

A key component to any jQuery plugin is the ability to extend what it can do. Exposing the plugins methods and properties allows developers to build on and customize the plugin to suit their needs. Though, be sure to only expose the elements that will be used. The outside world shouldn’t have access to all internal methods and properties.

In the example above, the exposed API should only include a call to the updateSymbol() method. The internal getData() method runs automatically when the symbol get’s updated so the public doesn’t need access to it.

Exposing an API requires you return an object with any of the desired methods and properties at the end of the plugin code. The best part of this is you can return methods and properties within the module code—this is the beauty of a well-organized module pattern.

;(function($, window, document) {
  $.realTimeStocks = function(options) {
    var rts = {
      options: $.extend({
        'updateDuration': 3000,
        'postURL': 'stockMarketAPI.php'
      }, options),
      getData: function(sym) {
        ...
      },
      updateSymbol: function(sym) {
        ...
        this.getData(sym);
      }
    };
  };
  
  return {
      update: rts.updateSymbol(sym),
      someMethod: function( ) { … }
  }
})(jQuery, window, document);

API method and properties are now available through the object returned from the plugin initialization.

var rts = $.realTimeStocks({
  updateDuration: 5000,
  ...
});

rts.update('AAPL');

A Beautiful jQuery Plugin

With the module pattern described above, we’ve got ourselves a beautiful, reusable, extensible plugin that will make developers lives easier. Like with any project, experiment with this structure so it works for you, your team, and your workflow. Check out jQuery Boilerplate and an article by Addy Osmani that describes some essential jQuery plugin patterns.

/*!
 * jQuery lightweight plugin boilerplate
 * Original author: @ajpiano
 * Further changes, comments: @addyosmani
 * Licensed under the MIT license
 */


// the semi-colon before the function invocation is a safety 
// net against concatenated scripts and/or other plugins 
// that are not closed properly.
;(function ( $, window, document, undefined ) {
    
    // undefined is used here as the undefined global 
    // variable in ECMAScript 3 and is mutable (i.e. it <span class="hiddenGrammarError" pre="and "><span class="hiddenGrammarError" pre="and ">can 
    // be</span></span> changed by someone else). undefined isn't really 
    // being passed in so we can ensure that its value is 
    // truly undefined. In ES5, undefined can no longer be 
    // modified.
    
    // window and document are passed through as local 
    // variables rather than as globals, because this (slightly) 
    // quickens the resolution process and can be more 
    // efficiently minified (especially when both are 
    // regularly referenced in your plugin).

    // Create the defaults once
    var pluginName = 'defaultPluginName',
        defaults = {
            propertyName: "value"
        };

    // The actual plugin constructor
    function Plugin( element, options ) {
        this.element = element;

        // jQuery has an extend method that merges the 
        // contents of two or more objects, storing the 
        // result in the first object. The first object 
        // is generally empty because we don't want to alter 
        // the default options for future instances of the plugin
        this.options = $.extend( {}, defaults, options) ;
        
        this._defaults = defaults;
        this._name = pluginName;
        
        this.init();
    }

    Plugin.prototype.init = function () {
        // Place initialization logic here
        // You already have access to the DOM element and
        // the options via the instance, e.g. this.element 
        // and this.options
    };

    // A really lightweight plugin wrapper around the constructor, 
    // preventing against multiple instantiations
    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName, 
                new Plugin( this, options ));
            }
        });
    }

})( jQuery, window, document );

Author: Ben Marshall

Red Bull Addict, Self-Proclaimed Grill Master, Entrepreneur, Workaholic, Front End Engineer, SEO/SM Strategist, Web Developer, Blogger

Leave a Reply

Your email address will not be published. Required fields are marked *