A take on modularity in JavaScript

  1. Making code modular and solid is always a challenge. Recently, when re-developing a small application, I wanted to focus on modularity. After fiddling a bit with my JavaScript files I came up with a better and simpler way to modularize my code.

    Making code modular and solid is always a challenge. Recently, when re-developing a small application, I wanted to focus on modularity. After fiddling a bit with my JavaScript files I came up with a better and simpler way to modularize my code.

    I had several components that needed something to be done at page load. I had already written a bit of jQuery code to do what was necessary. My functions and page ready block grew and grew. It just wasn't very maintainable. I had already modularized my components in terms of CSS stylesheets, so I thought there must be an easier way, without going full OOP for such a small application.

    Personally I love jQuery, but it's power doesn't come without it's pitfalls. Your code can easily become a monsterous single-file nightmare. Thus I present my take on this challenge. It may not be rocket science and may have it's limitations, but it's really easy to implement and immidiately helps out!

    API object

    I came up with the idea to create a simple object as a base. I decided to call it the "API" object. That's basically what it is, a JavaScript API for an application. It contains global functions and an init function. This function is run at page ready.

    var myapp = {
    
      /**
       * Initializes the application and it's components.
       */
      init: function() {
        
        var api = this;
        var instance;
            
        $(".myapp").each(function(i){
            
          instance = $(this);
          
          //Initialize here
          
          //Iterate through all modules (objects) and call their init function
          var obj, key;
          for(key in api) {
            if(api.hasOwnProperty(key) && (typeof api[key]) === "object") {
              obj = api[key];
              if(obj.hasOwnProperty("init") && (typeof obj.init) === "function") {
                obj.init(api, instance);
              }
            }
          }
          
        },
        
      /**
       * Does something
       * 
       * @param   instance    an application instance object
       */
      doSomething: function(instance) {
        }
        
    }
    
    $(function(){
      myapp.init();
    });

    The function does some application-global initialization and then it looks through the API object for properties that are objects. You see, each component of the application are added to the API object as extensions, before page ready. If an extension has an init function of it's own, it is called automatically. All we do is initialize the application: myapp.init();

    Extensions

    To make this happen, first the API object should be loaded. Then we load each component and extend the object with jQuery's extend function. Now we can be sure that the initialization will be done at page ready and we can add whatever functions we want in it's own API object. To use them we simply call them like this: myapp.mycomponent.dosomething();

    $.extend(myapp, {
      mycomponent : {
        
        
        /**
         * Init function
         * 
         * @param   api       the api object
         * @param   instance  an application instance object
         */
        init: function(api, instance){
        
            var inst;
            $(".mycomponent").each(function(i) {
              inst = $(this);
              //Initialize here
            });
      
          },
          
        /**
         * Does something
         * 
         * @param   inst      a component instance object
         */
        doSomething: function(inst){
          }
        
        
      }
    });

    In addition to my components I added a utility extension for functions solving common problems. This all enables us to keep things modular. If we need to add a component, we create a new JavaScript file and it's ready for use. We have rid ourselves of long, messy single-file code. And it's really very simple!

    As an extra step I thought it would be good practice to ensure that my components all run on their preferred version of jQuery. The library has a function $.noConflict() which is there for just that kind of things. Combined with closures, the end result is as follows.

    <script type="text/javascript" src="jQuery-1.4.2.js"></script>
    <script type="text/javascript">
      var jQuery142 = jQuery.noConflict();
    </script>
    <script type="text/javascript" src="myapp-1.0.0.js"></script>
    <script type="text/javascript" src="myapp-mycomponent-1.0.0"></script>
    var myapp = {};
    
    (function($){
    
      $.extend(myapp, {
      
        init: function(){
          },
        doSomething: function(instance) {
          }
          
      });
    
      $(function(){
        myapp.init();
      });
    
    })(jQuery142);
    (function($){
    
      $.extend(myapp, {
        mycomponent : {
    
          init: function(api, instance){
            },
          doSomething: function(inst){
            }
    
        }
      }
    
    })(jQuery142);