DEV Community

Cover image for The Revealing Module Pattern in JavaScript
Nick Scialli (he/him)
Nick Scialli (he/him)

Posted on • Originally published at typeofnan.dev

The Revealing Module Pattern in JavaScript

You can use the revealing module pattern in JavaScript to maintain private information using closures while exposing only what you need.

The Problem

Let's consider the following example where we create the object clarkKent.

const clarkKent = {
  name: 'Clark Kent',
  secretIdentity: 'Superman',
  introduce: function() {
    return `Hi, my name is ${this.name}.`;
  },
  issuesReport: function() {
    return `${this.secretIdentity} saves the day!`;
  },
};

Using this example, Clark can introduce himself and can report that Superman saved the day:

console.log(clarkKent.introduce());
// Hi, my name is Clark Kent.
console.log(clarkKent.issuesReport());
// Superman saves the day!

This is great, but, oh no! We have access to Clark's secret identity!

console.log(clarkKent.secretIdentity);
// Superman

The Revealing Module Pattern to the Rescue

One way we can get around this issue is by using the revealing module pattern. The revealing module pattern uses an Immediately Invoked Function Expression (IIFE) to create closure around variables we want access to within the module but don't want to expose to the world.

Let's see how this works out for Clark.

const clarkKent = (function() {
  const name = 'Clark Kent';
  const secretIdentity = 'Superman';
  const introduce = function() {
    return `Hi, my name is ${name}`;
  };
  const issuesReport = function() {
    return `${secretIdentity} saves the day!`;
  };

  return { introduce, issuesReport };
})();

console.log(clarkKent.introduce());
// Hi, my name is Clark Kent.
console.log(clarkKent.issuesReport());
// Superman saves the day!
console.log(clarkKent.secretIdentity);
// undefined

Perfect! We've created a closure around the secret information we don't want to expose and only revealed the introduce and issuesReport methods from our module!

Conclusion

While this is a bit of a silly example, it's important to note that we have tools and patterns at our exposure to maintain privacy and, importantly, not expose imformation beyond where it's really needed.

Discussion (6)

Collapse
sergix profile image
Peyton McGinnis

Very creative presentation of the topic!

Collapse
omrisama profile image
Omri Gabay

Interesting. Would you say this is an alternative to using ES6 classes? I've seen a lot of people push against those for different reasons.

Collapse
brunnerlivio profile image
Livio Brunner • Edited on

I would not say its directly an alternative to ES6 classes since they need to be instantiated and can have its own context per instance. With this example, you will share the context with every call, similar to a static class. In fact, if you have the following example in TypeScript or ES6:

class clarkKent {
  private static fullname = 'Clark Kent';
  private static secretIdentiy = 'Superman';
  static introduce() {
    return `Hi, my name is ${this.fullname}`;
  }

  static issueReport() {
    return `${this.secretIdentiy} saves the day!`;
  }
}

and you compile it to ES5, you will end up with almost the same code as the author described.

var clarkKent = /** @class */ (function () {
    function clarkKent() {
    }
    clarkKent.introduce = function () {
        return "Hi, my name is " + this.fullname;
    };
    clarkKent.issueReport = function () {
        return this.secretIdentiy + " saves the day!";
    };
    clarkKent.fullname = 'Clark Kent';
    clarkKent.secretIdentiy = 'Superman';
    return clarkKent;
}());

The benefit of using this module pattern over static classes is to get rid of the this keyword. From a user perspective, they behave pretty much the same though. One thing to take into account is that ES6 static classes' private properties can be accessed if you disable the TypeScript compiler. With the module pattern, it will get very hard (if not impossible) to access those.

Collapse
pavelloz profile image
Paweł Kowalski

Im pretty sure es6 class doesnt have to be instantiated to do some of those things.

IE.

class Test {
  static hello() { console.log('world'); }
}

Test.hello(); // => 'world'
Thread Thread
brunnerlivio profile image
Livio Brunner

I think you are referring to:

ES6 classes since they need to be instantiated

I was not referring to static classes here :) I thought it would be clear with the rest of my comment.

Thread Thread
pavelloz profile image
Paweł Kowalski

Well, class is not static, it just has static methods on it, you can still do everything you do with any other class, plus you can run methods directly, which in combination gives a lot of flexibility.