What is Module Pattern?
Modules are an integral part of any robust application's architecture and typically help in keeping the units of code for a project both cleanly separated and organized.
The module pattern is a common JavaScript coding pattern. To understand Module Pattern you should have knowledge about the Closure principle of JavaScript.
What is Closure?
Closures are a means through which inner functions can refer to variables present in their outer enclosing function after their parent
functions have already terminated. Here is an example for Closure:
function addGenerator(num) {
return function (toAdd) {
return num + toAdd
};
}
var addFive = addGenerator(5);
alert(addFive(4) == 9);
Example of Module Pattern
var EmployeeModule = (function () {
var employeeList = [];
return {
add: function (employee) {
employeeList.push(employee);
},
getAll: function () {
return employeeList;
},
totalCount: function () {
return employeeList.length;
}
};
})();
We can use our EmployeeModule
in this way.
EmployeeModule.add({ Id: '01', Name: 'Emon Khan', Designation: 'Software Engineer' });
EmployeeModule.add({ Id: '02', Name:'Khairul Islam', Designation: 'Senior Software Engineer'});
EmployeeModule.getAll();
Module Pattern Variations
The Revealing Module Pattern
The Revealing Module pattern came from the fact that we need to repeat the name of the main object when we want to call
a public method from another or access public variables. Another problem is, if the Module code is too large it is difficult to see which methods or variables are public and which are not. As a result an updated pattern comes into play where we would simply define all of our functions and variables in private scope and return an anonymous object with pointers to the private functionality we wished to reveal as public.
An example of creating the Revealing Module pattern:
var EmployeeModule = (function () {
var employeeList = [];
var allEmployee = function () {
return employeeList;
};
var add = function (employee) {
employeeList.push(employee);
};
var totalCount = function() {
return employeeList.length;
};
return {
add: add,
getAll: allEmployee,
totalCount: totalCount
};
} ());
Advantages
This syntax of pattern is more consistent and more clear at the end of the module
where our functions and variables may be accessed publicly.
Disadvantages
A disadvantage of this pattern is that 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.
As a result of this, modules created with the Revealing Module pattern may be more fragile than those created with the original Module pattern, so care should be taken during usage.
Notes
If your Module does not require any overridden functionality then this approach is perfect for your application.
Extending Module Pattern
This is one of the powerful features of the Module pattern. For a large application different developers can work on different functionally on the same Module by extending the Module.
An example of extending the Module Pattern where the var
statement is not necessary:
var EmployeeModule = (function (my) {
my.anotherFunction = function () {
return alert('this is another function.');
};
} (EmployeeModule));
Loose Augmentation in Module Pattern
While our example above requires our initial module creation to be first, and the augmentation to happen second, that isn't always necessary. One of the best things
a JavaScript application can do for performance is to load scripts asynchronously. We can create flexible multi-part modules that can load themselves in any order
with loose augmentation. Each file should have the following structure:
var EmployeeModule = (function (my) {
return my;
}(EmployeeModule || {}));
In this pattern, the var
statement is always necessary.
Tight Augmentation in Module Pattern
While loose augmentation is great, it has some limitations. We cannot override module properties safely. We also cannot use module properties from other files during initialization
(but we can at run-time after initialization). Tight augmentation implies a set loading order, but allows overrides. Here is a simple example:
var EmployeeModule = (function (my) {
my.add = function () {
};
return my;
}(EmployeeModule));
Global Import in Module Pattern
We can also import other JavaScript libraries in our Module.
(function ($, Y) {
}(jQuery, YAHOO));
Sub-modules in Module Pattern
There are many cases where we can create sub-modules. It is just like creating a regular module.
EmployeeModule.subModule = (function () {
var my = {};
return my;
}());
Points of Interest
From my little experience I understood one thing, we can not only follow a design pattern in server side coding but also in client side
scripting. Module pattern is one of the best patterns for client-side scripting. It makes our client scripting more clear, consistent, understandable, and maintainable.
I have 3+ years industrial experience mostly Microsoft technologies. My expertise areas are Software development, design, use various design pattern to real life implementation, Unit testing, Java script, Knockout JS, Dojo, Ajax, ASP.NET Webform/MVC, SQL Server, NHibernet, Entity Framework etc.