JavaScript: The Power of the Module Pattern

JavaScript: The Power of the Module Pattern

In JavaScript, code encapsulation can be achieved using Modules Patterns. In addition, it is used to create private and public properties, a widely used and powerful pattern is the Module Pattern.

In JavaScript, a widely used and powerful pattern is the Module Pattern. It can be incredibly simple to implement but the fact that it enables developers to encapsulate their code makes it one of the most versatile patterns to build robust code. When you look inside the source code of JavaScript libraries, you're most likely looking at an implementation of this pattern--and they're most likely a singleton object meaning that only one instance exists throughout the lifetime of an app.

It may be difficult for newcomers in JavaScript to understand the module pattern as there are several variations that exist. However, it's worth all the time and trouble because you'll be using the module pattern very often to make your app more robust.

Modules

As you may have guessed, the module pattern lets you create modules. In the end, modules are basically just objects. But there are a couple of ways to create modules.

The most basic way to create a module is to assign an object to a variable like so:

const myModule = {
  drive() {
    console.log('*drives*')
  },
}

A simple image representation:

plain module

Things start to become more interesting when we utilize some of JavaScript's unique features to create a module, which we will cover next.

Immediately Invoked Function Expression

Arguably the most popular variation of the module pattern is the IIFE (Immediately Invoked Function Expression). These are essentially functions that invoke immediately and return an object (or an interface, in other words), which then becomes the module.

Inside these functions are code that can be private in such ways that they'd only be accessible within that function's scope unless the returned object provides methods that can access them somehow. This returned object is public to the outside world.

Here's an image representation of what this looks like, for those of you who are better at understanding things in a visual perspective:

module pattern using immediately invoked function expressions in javascript

We will implement our own module using an IIFE. This allows us to assign the return value of an IIFE directly onto a variable so that we can use it just like a JavaScript module.

For example, lets pretend that we are creating an RPG game and the first thing we decided to do was create a sorceress class. In general role playing games, sorcerers are highly powerful beings that possess strong magical abilities like fire, wind, electricity, etc. They commonly possess telekinetic powers to pick and move things around with just their minds. In just about every RPG game, sorceresses usually cast spells or magic, so we'll keep this concept in context when we define the interface for the sorceress.

const sorceress = (function() {
  const sideEffects = {
    intervals: {},
  }

  function _fireBolt(target, customDamage) {
    target.hp -= customDamage !== undefined ? customDamage : 15
  }

  function _thunderBolt(target) {
    target.hp -= 15
  }

  function blizzard(target) {
    target.hp -= 15
  }

  function _applyThunderBoltSideEffects(
    target,
    { interval = 1000, timeout = 15000 } = {},
  ) {
    if (sideEffects.intervals[target.id]) {
      clearInterval(sideEffects.intervals[target.id])
    }

    sideEffects.intervals[target.id] = setInterval(() => {
      target.hp -= 1
    }, interval)

    setTimeout(() => {
      if (sideEffects.intervals[target.id]) {
        clearInterval(sideEffects.intervals[target.id])
      }
    }, timeout)
  }

  return {
    fireBolt(target, options) {
      if (options) {
        _fireBolt(target, options.customDamage)
      } else {
        _fireBolt(target)
      }
    },
    thunderBolt(target) {
      _thunderBolt(target)
      _applyThunderBoltSideEffects(target)
    },
    blizzard,
    castAll(target) {
      this.fireBolt(target)
      this.thunderBolt(target)
      this.blizzard(target)
    },
  }
})()

In this example, our sorceress class has four methods available to use from the outside world: sorceress.fireBolt, sorceress.thunderBolt, sorceress.blizzard, and sorceress.castAll.

Inside this module, we declared three private functions and four public functions. We can obviously tell that that the functions prefixed with underscores _ are the private functions while latter are public. We know this because the ones with the underscores aren't being returned--instead some of them are just being used by the public methods. This concept of being able to reference local variables by lexical scope is called closure. Because we did not return the variables prefixed by underscores they are not available outside of the module--but they can be if the returned methods chooses to make that happen if desired.

Having the power to declare private and public variables this way is what makes the module pattern arguably the most powerful design pattern in JavaScript apps. The same pattern is essentially what's being constantly used today when we import or require from nodejs modules as well as including <script> tags that point to a library like jQuery.

Global Import

Uses of the module pattern in JavaScript is not limited to our previous code example. The module pattern in JavaScipt is powerful thanks to JavaScript's flexibility in nature. For example, JavaScript has a feature known as implied globals. If it's used in an assignment, the global is created if it doesn't already exist. So when we use or create global variables in anonymous closures, things can actually become easier to our favor to an extent.

Unfortunately however, the resulting issue is that our code becomes harder to manage over time because it is not obvious to us knowing which variables are global in a given file.

Luckily, anonymous functions provide an easy alternative. By passing in globals as parameters to our anonymous functions, they get imported into our code, which is both faster and clearer than implied globals.

Here's a code example illustrating this concept:

const myModue = (function(_) {
  // do stuff
})(lodash)

As you can see, we now have access to lodash as part of the global variable _

Here's an image representing what this may look like now:

global importing variables to modules in the module pattern inside javascript

Why Modules in General?

In general, there are multiple benefits to using modules.

Here are the most important:

It helps you maintain your code better

By definiton, a module is self-contained and should not rely on the outside world to survive. Updating a single module should be as easy as possible and should not break another part of the app when changed. A well module should be aimed to be well constructed and lessen the dependencies on parts of your code as much as possible so that they are decoupled from other parts of your code.

If we take a look at our sorceress class in the previous code example, we can already assume that if we try to change one of the methods defined inside, debugging would end up becoming a stressful process if it proceeded to break other parts of the codebase, especially if it creates a domino effect. Modules should be carefully designed in a way that any changes to them in the future doesn't end up affecting other parts of the code.

It helps us to avoid polluting the global namespace

In the JavaScript language, all variables located outside the scope of top-level functions are global. This means that other code can access them. This is problematic because it creates a situation called namespace pollution, where any completely unrelated code shares variables in the global scope, which is something you want to avoid at all times.

It helps us to reuse code

If you've been developing in JavaScript for awhile, you've probably found yourself copy and pasting code to multiple projects. This is fine until you start realizing that you had written the code snippet using bad practices and decide to rewrite it using better practices. If you had copy and pasted the code to multiple projects you are faced with the boring, repetitive task of having to go change every copy of the code if you wanted them to be applied the new changes. It would certainly become much easier to have a module that can be reused over and over so that you only need to update the module at one location in which consumers of the module will automatically be reflected of the changes every time.

Conclusion

And that concludes the end of this post! I hope you found this to be valuable, and look out for more in the future!

Javascript Module design pattern

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Deep Dive Into Design Patterns With JavaScript. The Builder Pattern

The builder design pattern allows for the creation of a complex object in a procedural manner. Imagine a scenario where you’re creating an application that allows the user to build their own house. Since you want your users to like your product, you provide them a tremendous amount of options. They can add pools, gardens, internet, walls, and even a roof (imagine that, a real roof!). There are several ways to approach this from a code perspective.

JavaScript Design Patterns

A pattern describes a Challange that happens over and another time in the environment, so describes the core of the answer thereto challenge, in such how that you simply will use this resolution a Tillion times over, without doing the same things twice.In application development,it is important to focus on the strategy of constructing, associating application in a very healthy, very strong, and easily maintainable approach, patterns offer a way of giving names to solutions for common challenges.

JavaScript Design Patterns - Command Pattern

JavaScript Design Patterns - Command Pattern. Command pattern is a data driven design pattern and falls under behavioral pattern category. What's the command pattern. Why the command pattern is important. How to implement the command pattern in JavaScript. When to use the command pattern. The idea of the command pattern is to create an abstraction between the operations an object can do, its commands, and the actual commands themselves

JavaScript Design Patterns: The Adapter Pattern

This time we are going to dive into Adapter pattern. Which is one of the simplest but really powerful and underestimated patterns out-there. What is a Design Pattern? Adapter pattern in JavaScript: Adapter is a structural design pattern so it can improve quality and scalability of your code, massively

JavaScript Design Patterns: The Factory Pattern

Lets make it not boring. Explaining Factory Pattern with simple words. We are going to dive into Factory Pattern and how to make use of it in JavaScript.