Design pattern in JavaScript: Part 1

Design pattern in JavaScript: Part 1

Module Pattern

Table of contents

Frontend development has evolved a lot in recent times and everyone is looking to build modular codebases by abstracting components to have a defined separation of concerns. Design patterns are not algorithms or implementations. It’s more of ideas, abstractions, and reusability that can be helpful in certain situations to solve a particular problem.

In this series, I want to discuss some common patterns to improve your programming and dive deep into JavaScript internals. We’ll be discussing the following design patterns in this post:

  • Module
  • Prototype
  • Observer
  • Singleton

For this post, we'll discuss Module patterns, why we need them, how we can implement them, and are pros and cons of using this pattern.

Module design pattern

Since JavaScript doesn’t natively support classes, although it is considered a prototype-based language. The class syntax introduced in ECMAScript 2015 is primarily syntactical sugar over the existing prototype-based inheritance.

The module pattern is used to emulate the concept of classes in such a way, we’re able to shield particular code from the global scope. The pattern allows to access public methods and variables while keeping private methods/variables encapsulated from others.

Since we cannot declare variables as being public or private, so we use function scope to simulate this. We use Immediately-Invoked Function Expression(IIFE) pattern to execute the function instantly after it’s defined, to ensure variables are only accessible within the scope of the defined function. Let’s see how we can implement this pattern that is self-contained.

var countModule = (function () {
  var counter = 0;
  return {
    incrementCounter: function () {
      return ++counter;
    },
    resetCounter: function () {
      console.log("counter value prior to reset: " + counter);
      counter = 0;
    }
  };
})();

// Usage:

// Increment our counter
countModule.incrementCounter(); // 1
countModule.incrementCounter(); // 2
countModule.incrementCounter(); // 3

// Logs current counter and reset counter to 0
countModule.resetCounter();

// Accessing counter
console.log(countModule.counter) // undefined

Here, the counter variable is shielded from global scope so it acts private and its existence is limited to the module’s closure.

Summing up the pros and cons:

Pros

  • Ability to modularize scripts in reusable objects
  • Variable & Functions are removed from the global scope
  • Ability to implement private and public methods as needed

Cons

  • It’s not memory efficient like the prototype pattern is. Functions get duplicated across many objects in memory.
  • Extending and overriding functionality in the module is lost since we don’t have prototypes
  • It can be difficult to debug when some members become private scope.

Next, we’ll be understanding the Prototype pattern. How it can help us use inheritance between objects without consuming much memory.