Module Pattern in JavaScript

JavaScript Modules

In JavaScript, there is a pattern you should be familiar with. That pattern is the module pattern. There are three main reasons why using this pattern or understanding where this pattern is used can be helpful and enable you to write better and more usable code.

Maintainability

Using the module pattern can help you to create code that is more maintainable. This is for the reason that writing your code into modules means that it should have fewer dependencies and writing an update to a module is only going to affect that module. This is often referred to as loosely coupled code in object-oriented design. Think of it as the ability to change the tire of a car without having to change the axle, or even worse the change the engine out.

Namespace Pollution

If you have ever run into global namespace collision you’ll understand why modules are helpful when creating an application. For instance, you have two different JavaScript files, and they both have a variable with the same name. If these variables are declared in a way where they become global, they can impact the other and variable values change. This applies to function and objects declared well if they both intercede into the global namespace. Modules are meant to allow a private namespace and lessen the likelihood of namespace pollution.

Reusability

Keeping your code dry (don’t repeat yourself) is not always easy. We’ve all been guilty of this one. ctrl + c and then a ctrl + v somewhere else. The issue with this is if you then later update your function or piece of code that you just copied, you have more than one place to update that now. Modules can help prevent this and allow you to reuse your code more easily.

Closure

You also need to understand the concept of closure to really understand how modules work. Much of this is done under the hood in the ES6 implementation of JavaScript and I will cover this next time in an ES6 module post, but I want to also show how things have been done not so long ago, as there is still a lot of value in this and will help you to better understand legacy code and also how things are done under the hood in ES6.

Closure is simply how objects and variable declared in relation to the surrounding curly brackets, or in other words their scope. For example, the following snippet of code is incrementing a variable declared outside of the increment function. This is perfectly valid code, just realize that the counter variable and increment functions are global in scope.

Anonymous Function Pattern

let counter = 0;
 
// function to increment counter
function increment() {
    counter += 1;
    return counter;
}
 
// increment() 3 times
increment();
increment();
console.log(increment()); //3

So how would we abstract some of this away then so that our variables and functions are not global in scope? This can be done by using an anonymous function to bring about the closure and remove our variables from the global window scope.

(function () {
   let counter = 0;
 
   // function to increment counter
   function increment() {
       counter += 1;
       return counter;
   }
   // increment() 3 times
   increment();
   increment();
   console.log(increment()); //3
}());

Global Imports and Global Namespace

But what if we wanted to pass something into our anonymous function from the global namespace? This is often referred to as a global import. So in this example, we are simple incrementing a global variable and modifying it through our anonymous function. Not much of a difference you might be saying and in this case is true. However, this is a pattern that you’ll often see when loading a script and modifying or updating a global variable. Notice the ending callback function that is actually taking in our globalCounter variable. It then increments the globalCounter but limits the scope to our anonymous function. Following that we console.log(globalCounter) after the anonymous function has been called and returns us the initial value of 0 showing us that indeed the global variable was not modified.

let globalCounter = 0;
 
(function (counter) {
 
 
   // function to increment counter
   function increment() {
       counter += 1;
       return counter;
   }
 
   // increment() 3 times
   increment();
   increment();
  console.log(increment()); //3
}(globalCounter ));
console.log(globalCounter);//0

Object Interface and Revealing Module Pattern

These two patterns are very similar and it really depends on what type of access you want to allow access to your module. If you are familiar with object-oriented patterns and public and private access modifiers this is how you can simulate this in JavaScript. The following snippet has refactored out our counter to a useable object where we can call our increment function. We are directly accessing the object’s function to increment. There is something to be aware of though. Using this object interface will allow you to redefine the function later on. I can set counterModule.increment = undefined and change the behavior. This is a bit of a code smell.

let counterModule = (function () {
 
   let  counter = 0; 
   return {
      increment: function() {
       counter += 1;       
       return counter;
     }
   }
 
}());
 
counterModule.increment();
counterModule.increment();
counterModule.increment();//counter = 3

So what is the fix for preventing this type of dilemma? This is where using the revealing module pattern comes in. Notice that the code for our counterModule is almost the same snippet as above, the only difference is we are returning an object with its property bound to our function. This reveals only the code that we want to and can allow us to have private functions that we don’t necessarily want to reveal with the log() function for example. This is a roundabout way to have a private function on our counterModule

let counterModule = (function () { 
  let  counter = 0; 
 
  function log(){
    console.log('incrementing');
  }
 
  function increment() {
    counter += 1;   
    log();
    return counter;
  }
 
  return {
    increment : increment
  }
}());
counterModule.increment();
counterModule.increment();
counterModule.increment();//counter = 3

Libraries for Expediting your Modules and Dependencies

There are a few libraries out there AMD and CommonJS are some of the more popular that seeks to help out with writing your own modules, and I’d recommend using them when working on large applications. There are often times where a module you’ll have written can have a dependency and using these libraries assists with loading dependencies and helps to reduce some of the headaches of figuring out which where to place a dependencies script tag. If you’ve seen the module.exports = myModule or let myModule = require('myModule'); then you’re looking at commonJs loading of modules. AMD does things a little differently, and looks like this define(['myModule', ], function(myModule) {
console.log(myModule.increment());
});

As always, I hope you found this useful. I’ll be covering the ES6 implementation of modules in my next post so stay tuned.