Modules

Modules are an essential part of any robust application’s design and it is usually help to keep our code units both cleanly separated and organized.

The module pattern is partly based in the Object Literals so it makes sense to freshen up our understanding, before we dive in the actual specifics of the pattern.

Object Literals

In object literal notation, an object is represented as a set of key/value pairs enclosed by curly brackets { }. Names (or keys as called) are either strings or identifiers followed by a colon (:). The values can be anything, strings, integers, functions, objects etc followed by a comma (,). Note that here should be no comma used after the final name/value pair in the object as this may result in errors.

var myObject = {
    variableKey: variableValue,  // a variable key/value pair
    functionKey: function(){
        console.log("Hello there!");
    } // a function key/value pair
};

A more complete example of a module using object literals is the following:

var myModule = {
  someProperty: "some value",

  //We can add other objects in our object literal.
  someConfig: {
      useCaching: "true",
      language: "en",
      version: 1.0
    },

    // Some basic method
    saySomething: function() {
        console.log("Hello there! I am a module!");
      },

      // Log some property of the module
      reportConfig : function() {
        console.log("Current Configuration:\nCaching: " + this.someConfig.useCaching + "\nLanguage: " + this.someConfig.language + "\nVersion: " + this.someConfig.version);
      },

    changeLanguage: function(lang){
        console.log("Previous language: "+this.someConfig.language);
        this.someConfig.language = lang;
        console.log("Current language: "+this.someConfig.language);
    }
};

// logs "Hello there! I am a module!"
myModule.saySomething();

//logs Current Configuration:
//     Caching: true
//     Language: en
//     Version: 1
myModule.reportConfig();

//logs Previous language: en
//     Current language: el
myModule.changeLanguage("el");

The Module Pattern

In JavaScript, the Module pattern is used to emulate the classes used by object-oriented languages such as Java and C#. This pattern gives us a way to include both private/public methods and variables under a single scope, thus shielding the module’s members from global scope. This lowers the chances of conflicting names defined by other scripts in the page.

Note that the module pattern uses an immediately-invoked function expression (IIFE).

var sampleModule = (function(){
    // Private variables and functions
    var welcome = "Welcome";
    
    var getWelcome = function(){
         return welcome;
    };


    return{
        welcomeSomeone: function(name){
            console.log(getWelcome()+" "+name);
        }
    };
}());

// logs Welcome Kalkost
sampleModule.welcomeSomeone("Kalkost");

// throws a TypeError
sampleModule.getWelcome();

As you can see, the pattern makes the inner object functions private and the public methods are returned. The public functions have access to the private functions and variables, but the private ones are inaccessable.

Advantages

For starters, it’s a lot cleaner for developers coming from an object-oriented background than the idea of true encapsulation, at least from a JavaScript perspective.

Secondly, it supports private data – so, in the Module pattern, public parts of our code are able to see the private parts, however the outside world is unable to see the class’s private parts.

Disadvantages

First of all, we access both public and private members differently, when we wish to change visibility, we actually have to make changes to each place the member was used.

Moreover, we can’t access private members in methods that are added to the object at a later point.

The Revealing Module Pattern

The Revealing Module Pattern takes a slightly different approach when returning public methods. Instead of just returning the actual public functions we return public methods as pointers to the private ones. The problem that arises here is that if we have to override a public function or patch it up, and that function refers to a private function which in turn refers to another, the second function will be inaccessible since it will be out of scope. It is a bit confusing, so check out the following example:

var revealingModule = (function() {
  var _welcome = "Welcome";

  var _getWelcome = function() {
    return _welcome;
  };

  var welcomeSomeone = function(name) {
    console.log(_getWelcome() + " " + name);
  };

  // Public vars and functions
  return {
    sayWelcome: welcomeSomeone
  };
}());
// logs Hello Kalkost
revealingModule.sayWelcome("Kalkost");

//Trying to override here...
revealingModule.sayWelcome = function(name){
  console.log(_getWelcome() + " to the store! " + name);
};

// and this, throws a ReferenceError, since sayWelcome is out of scope.
revealingModule.sayWelcome("Kalkost");

Advantages

This pattern allows the syntax of our scripts to be more consistent. It also makes it more clear at the end of the module which of our functions and variables may be accessed publicly which eases readability.

Disadvantages

If a private function refers to a public function, that public function can’t be overridden if a patch is necessary. This is because the private function will continue to refer to the private implementation and the pattern doesn’t apply to public members, only to functions.

Public object members which refer to private variables are also subject to the no-patch rule notes above.

Advertisements