In JavaScript application, the module pattern is a popular design pattern that encapsulates ‘privacy’, state and organization using closures. A module helps keep units of code cleanly separately and organized. It provides a way of wrapping a mix of public and private methods and variables, protecting pieces from leaking into the global scope and accidentally colliding with another developer’s interface. No matter if you are using any JavaScript framework or not, module pattern is one of the best practices in JavaScript development to organize and limit code scope in any project. Module pattern helps you to structure your code base more towards a Object-Oriented fashion as we are doing in C# or Java.
- The JavaScript language doesn’t have class, but we can emulate what classless can do with modules.
-
A module helps encapsulate data and function into a single component
-
A module limits scope so the variables you create in the module only live within it.
-
A module gives privacy by only allowing access to data and functions that the module wants to expose.
Basic Module Pattern Structure
The core of module pattern is based on IIEF (Immediate Invoked Function Expression). It is a anonymous function, execute immediately. All of the code run inside the function lives in a closure, which provide privacy and state through the life time of the application.
// All Private (function() { // Detail logic goes here }()); //calling this method.
The code snippet above hide all of your implementation from external code. The function runs once and only once.
Module Pattern and Variations
Anonymous Object Literal
A version evolved from the simple IIEF is return a anonymous object literal that would expose privilege methods
var Module = (function() { // private ... var privateVariable = "some priviate value", privateMethod = function() { //do something. }; return { //the method inside the return object are //called as privileged method because it has access //to the private methods and variables of the module. privilegedMethod: function() { //this method can access its private variable and method by using the principle of closure. console.log("outputting " + privateVariable); //accessing private variable. privateMethod(); //calling private method } }; })();
By using the principle of closure, the privileged method can access its private variables and methods. The returned object literal will be added to Window (global) name space. It returns the only parts we needs, leaving the other code out of the global scope.
Locally scoped object literal
Another variation is to create and return an object containing all of the public members as its properties.
var Module = (function() { // locally scoped Object var myObject = {}; // declared with 'var', must be "private" var privateMethod = function() {}; myObject.someMethod = function() { // make it a public method }; return myObject; // only the object send back, not the name })();
Again, the private member inside the module is created using closure. The module is created by using anonymous function expression. Any declared function or variable will be private unless they are added as properties to the returned public object.
Revealing Module Pattern
Revealing module pattern is very common pattern, widely used JavaScript applications. Comparing with Locally scoped object literal version above, Revealing Module Pattern doesn’t create a separate returned object and then adding properties to it. But instead, we define all the function private first, then decide which ones should be public by return those methods as properties of an anonymous object literal.
var Module = (function() { var privateMethod = function() { // private }; var someMethod = function() { // public }; var anotherMethod = function() { // public }; return { someMethod: someMethod, anotherMethod: anotherMethod }; })();
it is a very flexible variation of Module Pattern. It can better control the name of the public API. If it is required to change the name, all we need to do is to change the name from the returned object without any impact of the function name inside the module. Also, it controls what should be public by adding/removing the properties.
Common Practices
Passing External Library
Most of time, our module needs to reference other third party libraries, like jQuery or Kendo. JQuery uses ‘$’ as shortcut to reference JQuery element, but ‘$’ is not just used by jQuery. To avoild confilict, it is a common practices to pass ‘$’ as a parameter to the Module.
var Module = (function($) { var privateMethod = function() { // private }; var someMethod = function(x) { // use jQuery function/features if ($.isArray(x)) { // do something } }; var anotherMethod = function() { // public }; return { someMethod: someMethod, anotherMethod: anotherMethod }; })(jQuery);
Reference Other Modules
Module can be referenced by other modules, which provides a compsite solution.
var Module01 = (function() { var sayHelloPrivate = function(name) { console.log("Hello, " + name); }; return { sayHello: function(name) { sayHelloPrivate(name); } }; }()); var Module2 = (function(m1) { return { startThingsOff: function(name) { m1.sayHello(name); } }; }(Module01));
Extending Module Pattern (augmentation)
Module can be extended or overwritten by other module as well.
// extending and overwriting the module var Module1 = (function(oldModule) { var //assigning oldmodule in to a local variable. parent = oldModule; //overriding the existing privileged method. parent.privilegedMethod = function() { //do something different by overriding the old method. }; //private method accessing privileged method of parent module. var privateMethod2 = function() { //can access privileged method of Module parent.privilegedMethod(); //can access public method of Module parent.publicMethod1(); } return { newMethod: function() { ///do something for this brand new module. ///use some functionality of parent module. /// parent.privilegedMethod( ); } }; })(Module); //Module object is the existing module that I want to extend.
Passing Name Space Parameter
Besides other module or library can be passed to the module as argument, it is very common practice to take name space parameter to define name space for the module.
(function(skillet, $, undefined) { //Private Property var isHot = true; //Public Property skillet.ingredient = 'Bacon Strips'; //Public Method skillet.fry = function() { var oliveOil; addItem('tn Butter nt'); addItem(oliveOil); console.log('Frying ' + skillet.ingredient); }; //Private Method function addItem(item) { if (item !== undefined) { console.log('Adding ' + $.trim(item)); } } }(window.skillet = window.skillet || {}, jQuery));
Consideration of Multiple Instance
If the module will be created multiple instance, we can apply prototype to save memory. Because, instead of each instance having a copy of the member, the single prototype member is shared. So we can return a constructor function from the module.
// code from http://stackoverflow.com/questions/21909785/java-script-revealing-module-pattern-create-multiple-objects var Slider = (function($) { function slider(id) { this.id = id; } slider.prototype = { init: function() { this.pageLoad(); }, pageLoad: function() { console.log('pageLoad called from instance with id', this.id); }, getId: function() { return this.id; // <- 'this' refers to the current instance } }; return slider; })(jQuery); var slider1 = new Slider(1); var slider2 = new Slider(12);
Organizing Modules with different Files
We already see how to extend the module previously. In some situation when the JavaScript module is overly complicate, We can apply this approach to separate the module into multiple files. You see, in the same below, I split the entire Module implementation into two separate files. If we understand how the module references to be extended, we will have no problem understand this code structure. In both files, it take Module as parameter to extend its functions.
// Module.js var Module = (function($, pub) { // jQuery will still be available via $ var mem = new Array(); //private variable pub.publicMethod01 = function(val) { mem.push(val); }; pub.publicMethod02 = function() { return mem.pop(); }; return pub; })(jQuery, Module || {}); // Module-Additional.js var Module = (function($, pub) { pub.publicMethod03 = function(val) { // do something }; pub.publicMethod04 = function() { // do something else }; return pub; })(jQuery, Module || {});
Wrap up: Today I walked through the Module Pattern, it variations and some common usage. I don’t intend to give very detailed explanation of Pro and Con of each of them. I hope we can start to use this elegant pattern. It is first step to get our JavaScript code organized.