Introduction
In this article, we will look at two popular JavaScript design patterns, the module, and revealing module patterns.
Usually, object-oriented languages such as Java provide 'private', 'protected', and 'public' access modifiers which help us to protect the variables and functions/methods using the keyword 'private'.
Unfortunately in JavaScript, the default access level is global and care should be taken to protect the variables and functions that you do not want to expose and Module pattern provides an elegant way to do it.
Let us dive in to understand the pattern and create code snippets with both module and revealing module pattern.
Module Pattern
I will strongly recommend that you spend a few minutes to read this article to understand what an IIFE (Immediately Invoking Function Expression) is. The Module pattern is based on IIFE and hence it will give you the right foundation before proceeding further.
Now that we have the fundamentals of IIFE in place, let us look take a step-by-step approach to create a module pattern.
Step 1:
We will first create an IIFE and assign it to the constant module.
const module = (function() {
//private variable
const person = {
name: 'Skay',
age: 38
}
//private function
function addProperty(propName, propValue) {
person[propName] = propValue;
//Displays the value of person object after a new property has been added
console.log(`The Person object after addProperty function is executed is ${JSON.stringify(person)}`);
}
//Displays the initial value of the person object
console.log(`The Initial value of Person object is ${JSON.stringify(person)}`);
}());
The output when you run the above code snippet will be: "The initial value of Person Object is {"name": "Skay", "age":38}".
The IIFE contains a private 'person' object and a private function 'addProperty' that accepts a property name and a property value.
Two things to note:
- If you console.log(module), then you'll get 'undefined' since nothing is returned by this function.
- The function 'addProperty' will not be invoked while running the IIFE and hence the console.log statement inside the function will not run.
Step 2:
Let us look at the below code snippet for the next steps involved.
const module = (function() {
//private variable
const person = {
name: 'Skay',
age: 38
}
//private function
function addProperty(propName, propValue) {
person[propName] = propValue;
//Displays the value of person object after a new property has been added
console.log(`The Person object after addProperty function is executed is ${JSON.stringify(person)}`);
}
//Displays the initial value of the person object
console.log(`The Initial value of Person object is ${JSON.stringify(person)}`);
//You can return a variable or function that the outside world will have access to
return {
callAddPropertyFn: function(propName, propValue) {
//call the private function addProperty
addProperty(propName, propValue);
}
}
}());
//You can invoke the callAddPropertyFn since it's returned by the IIFE
module.callAddPropertyFn('gender', 'Male');
Let us look at the details of the above code snippet:
- We return a public method 'callAddPropertyFn' from the IIFE. The method will be returned to the 'module' variable. You can verify it by adding a console.log(module) outside the IIFE. You should get an output like this "{callAddPropertyFn : fn}".
- Since the function 'callAddPropertyFn' is inside the IIFE, it has access to all private variables and functions.
- You can invoke the function 'callAddPrpertyFn' from outside the IIFE function as shown below.
The output when you run the above code snippet will be: "The Initial value of Person object is {"name":"Skay","age":38}"
"The Person object after addProperty function is executed is {"name":"Skay","age":38,"gender":"Male"}"
That's it! Now you know how to define a module pattern. Basically, we've created a module that's accessible globally while protecting the private members and functions that we do not want to expose.
Revealing Module Pattern
The revealing module pattern is exactly like the module pattern but with a small twist. Let us take the above example and add another method 'removeProperty' to the IIFE.
const module = (function() {
//private variable
const person = {
name: 'Skay',
age: 38
}
//private function - addProperty
function addProperty(propName, propValue) {
person[propName] = propValue;
console.log(`The Person object after addProperty function is executed is ${JSON.stringify(person)}`);
}
function removeProperty(propName) {
delete person[propName];
console.log(`The Person object after removeProperty function is executed is ${JSON.stringify(person)}`);
}
function displayPerson() {
console.log(`The value of Person object is ${JSON.stringify(person)}`);
}
return {
addProperty: addProperty,
removeProperty: removeProperty,
displayPerson: displayPerson
}
}());
module.displayPerson();
module.addProperty('gender', 'Male');
module.removeProperty('age');
If you look at the return statement, the values of variables and functions can be returned in a conventional JavaScript way. We are using the addProperty, removeProperty, and displayPerson as pointers to the private functions.
This is a very clean way of specifying the public members and functions that you want to define to the outside world. The biggest advantage of revealing module pattern as compared to the module pattern is the code readability aspect.
The revealing module pattern is used to provide an abstraction over private implementations by providing public APIs.
Conclusion
Both the module and revealing module patterns should be used to protect variables and functions that you do not wish to share with the outside world. I would favor revealing module pattern for it's a much cleaner way of defining public APIs and improving code readability.
Do let me know your thoughts and comments on the article. Don't forget to subscribe to my newsletter and connect with me on Twitter @skaytech