JavaScript Module Pattern example
Introduction
Encapsulation of code in Vanilla JavaScript is not so easy to achieve as it is with traditional OOP programming languages like Java or Python. For this reason and purpose, in JavaScript we can use the Module pattern. Module pattern can also be used as a singleton object where only one instance of the module exists. We can define Module pattern in various ways, but the way I did it here is the simplest way to use and understand, and this is what will be presented in this article. I will be using ES6 specification of JavaScript and IIFE ( Immediately Invoked Function Expression ) as this is the most uniform way to do it.
Create the Module pattern
We will begin by defining a function which is evaluated, and then immediately invoked so we don’t have to call the function separately. This is the IIFE that we have mentioned previously. This function is the focal point of our module. It is important to notice that IIFE has a private scope, this is important because later on we will define properties ( variables ) and methods inside the body of the IIFE.
Image 1 - create the module
Export the Module
Now we want to export our module which is done by assigning our IIFE to a variable. Furthermore, I will define different variables and methods that belong to the module - the IIFE. All this data is inside the IIFE, and for now, not accessible outside the IIFE - this is important. All this data is private, scoped only to the IIFE, but our Module pattern will make it all accessible from the outer scope, as we will soon see. The assignment to a variable is used to achieve the persistent form for our module function so we are able to call different methods outside of the module, even after the IIFE function finishes execution. The methods and properties that I'm using are pretty self explanatory as far as the semantics is concerned, so we can see that we have two imaginary user arrays, and two methods that push new users to these arrays. We will use this later to see the benefits of the Module pattern. I have also defined two additional properties usersAverageSalary
and usersAverageAge
to show that we can access these too ( or not, it all depends on the return statement ) regardless of their "private" scope. This is how closures work in JavaScript, and this is a very obvious similarity.
Image 2 - assign the module to a variable and define different properties and
Adding the return statement
We have four properties and two methods in the IIFE - which is basically our module functionality. I have added a return statment to the IIFE which returns the object. This object is consisted of addUser
method, userList
array and usersAvergeAge
property. The addUser
method will change the state of the userList
array, and this will be visible even outside of the IIFE scope. The usersAverageAge
property will also be visible outside the private scope of the IIFE, but if we try to get the usersAverageSalary
property outside the private scope, we will get an error. This goes to show how the return statement changes everything in this case, and exposes methods and properties to public scope - to put it simply, everything that we return is accesible outside of the original private scope, the IIFE scope. This return statement acts as a kind of a door that opens up to the world outside of the module. This is the essence of the Module pattern.
Image 3 - adding the return statement and exposing the private scope
Module Pattern in action
All our private properties that are not returned are also not available outside of the module. Only methods and properties that are contained within the returned object can access our private scope from the outside of the module. This gives us the ability to create private state and encapsulation within our code, but also to expose our module as a public API.
Image 4 - accessing private methods and properties outside of the module private scope
If we check our console logs after we run our script ( link the script to a simple index.html
file and run it ), we see that the addUserOnline
method returns a console error. This method is not returned by the module IIFE - and this is why it is not visible to the outer scope.
Image 5 - missing module method in the outer scope
Let's now comment out the line where addUserOnline
method is called, to see the rest of the execution. Now we can see all methods and mutated arrays ( we have added some users into the array and this is persistent ) in the console. The usersAverageSalary
returns undefined
. We can see that this property is not part of the return statement of our IIFE.
Image 6 - returned and undefined values of the Module in the console
With this we conclude our little story explaining the JavaScript Module pattern. Happy coding!