JavaScript Module pattern provides a way to wrap public, private methods (and variable) into a single entity and exposing only the public members to the world outside of module. This allows faster namespace resolution, avoid collision of the methods/variables with other global APIs since the namespace isn’t populated with all many functions, and obviously provides cleaner code.
Implementing a module is pretty simple, lets say we need to create a Calculator module.
To do so, we execute a function expression which returns an object containing all the public members as its properties.
CalcModule = (function() {
var pub = {};
pub.add = function(a, b) {
console.log('in add()', a, b);
return a + b;
};
pub.sub = function(a, b) {
console.log('in sub()', a, b);
return a - b;
};
return pub;
})();
Code language: JavaScript (javascript)
Here we create and execute an anonymous function and assigns the return value of the function to the variable CalcModule
. Inside the function, we have created an object ‘pub‘ and then simply add properties to this object which needs to be exposed to outside world (functions ‘add’ and ‘sub’ in our case). Since the function is anonymously executed, any local variables declared inside the function can still be accessed inside the CalcModule
but will not be available outside of module.
Now to use this calculator, we can simple write:
CalcModule.add(5,2) //returns : 7
CalcModule.sub(5,2) //returns : 3
Code language: JavaScript (javascript)
Note that as JavaScript doesn’t provide any access modifiers, the private members inside a module were created using closures. And the module itself was created using anonymous function expression.
Lets give our calculator the ability to store results in its memory. To do so we add a private variable ‘mem‘ and expose a function to retrieve data. Any declared function or variable will be private unless we add it as a property to the returned public object.
CalcModule = (function() {
var pub = {};
var mem = new Array(); //private variable
var storeInMemory = function(val) { //private function
mem.push(val);
};
pub.add = function(a, b) {
var result = a + b;
storeInMemory(result); //call to private function
return result;
};
pub.sub = function(a, b) {
var result = a - b;
storeInMemory(result); //call to private function
return result;
};
pub.retrieveFromMemory = function() {
return mem.pop();
};
return pub;
})();
Code language: JavaScript (javascript)
Usage:
CalcModule.add(2,10);
CalcModule.add(5,15);
console.log(CalcModule.retrieveFromMemory()); //outputs 20
console.log(CalcModule.retrieveFromMemory()); //outputs 12
Code language: JavaScript (javascript)
Once the basic module is ready, we can pass parameters in the module during its initialisation (effectively importing them inside the module). For eg, we would like to pass jQuery variable into our module so that resolving jQuery variable inside of module don’t have to search entire scope chain but is available locally. To do so we simply pass the ‘jQuery’ in the parenthesis used to execute the function expression. In this example, we use jQuery’s isNumeric()
function to check whether input provided is a number.
CalcModule = (function($) {
var pub = {};
var INVALID = 'invalid input';
pub.add = function(a, b) {
if ($.isNumeric(a) && $.isNumeric(b)) {
return a + b;
} else {
return INVALID;
}
};
pub.sub = function(a, b) {
if ($.isNumeric(a) && $.isNumeric(b)) {
return a - b;
} else {
return INVALID;
}
};
return pub;
})(jQuery); //passed 'jQuery' global variable into local parameter '$'
Code language: JavaScript (javascript)
Let say, due to overly complex module we want our module to be defined in different js files. And that too in a way so that the implementation is independent of the order of execution of js files (It might happen that one JS file gets loaded before another). In our example lets separate out ‘add’ and ‘sub’ functions into one js-file, and memory implementation into another file.
File: calc.js
var CalcModule = (function($, pub) {
//jQuery will still be available via $
var mem = new Array(); //private variable
pub.storeInMemory = function(val) {
mem.push(val);
};
pub.retrieveFromMemory = function() {
return mem.pop();
};
return pub;
})(jQuery, CalcModule || {});
Code language: JavaScript (javascript)
File: calc_functions.js
var CalcModule = (function($, pub) {
//jQuery will still be available via $
pub.add = function(a, b) {
var result = a + b;
pub.storeInMemory(result);
return result;
};
pub.sub = function(a, b) {
var result = a - b;
pub.storeInMemory(result);
return result;
};
return pub;
}(jQuery, CalcModule || {}));
Code language: JavaScript (javascript)
First things to notice in above code is passing of parameters into the module. We pass the same javascript module ‘CalcModule’ as argument into the anonymous function and which gets assigned to parameter ‘pub’. Inside the function, we add properties to this parameter ‘pub’, and then return the same variable which gets assigned back to CalcModule. Thus, we managed to extend the existing CalcModule with new properties.
Second thing to notice is the OR ( || ) condition in the call. This is what makes above files independent of each other with respect to order of execution. If the CalcModule doesn’t exists yet, a new object is created (using ‘{}’) and passed to the parameter ‘pub’ which is then assigned to CalcModule. This ability to allow loading of scripts in any order, converts a Strict Augmentation to Loosely Augmentation.
This functionality to extend the module with other members is called Augmentation. And if the order in which these modules are loaded is defined than its called a Strict Augmentation, or else if the order is not important as in example above, it is called Loose Augmentation.
A disadvantage of separating same module across different files is inability to share private variables between files. Above logic worked because we can pass the global variable CalcModule to different anonymous functions and add properties to it, but since CalcModule only exposes public APIs, different modules won’t be able share private members (remember private members are implemented using closures, and each anonymous function will have its own closure).
A variation of the module pattern is the Revealing Module Pattern. As described earlier, for creation of a module it is required to return an object form anonymous function which has all the public properties. So lets change the implementation of the second example as below:
CalcModule = (function() {
var mem = new Array(); //private variable
var storeInMemory = function(val) { //private function
mem.push(val);
};
var add = function(a, b) {
var result = a + b;
storeInMemory(result); //call to private function
return result;
};
var sub = function(a, b) {
var result = a - b;
storeInMemory(result); //call to private function
return result;
};
var retrieveFromMemory = function() {
return mem.pop();
};
return {
add: add,
sub: sub,
popMemory: retrieveFromMemory
};
})();
Code language: JavaScript (javascript)
Notice the changes here, we are not creating a separate ‘pub’ variable and then adding properties to it. But instead we define all the functions public or not in the same way, and then in the return statement create a new object and add properties to it.
This concluded the basics of module design pattern.
Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…
Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…
Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…
1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…
GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…
1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…
View Comments
Awesome dude.... Thank u very much for this post... Really cool..
This is an excellent explanation. Better than anything I found. Thank you.
Very nice and detailed explanation... +1
Fans of the Module Pattern & Revealing Module Pattern, can also try the Definitive Module Pattern:
https://github.com/tfmontague/definitive-module-pattern
quick, clean and detailed! Thank you!
Thank you very much for explaining in such a lucid way.
Great and simple explanation :) Thanks a lot...
This post helped me a lot in understanding JavaScript module pattern. Very well explained, have been struggling to find a way when I was creating one feature. Thanks a ton!!!