DEV Community

Cover image for Revealing Module Pattern in JavaScript
Adrian Bece
Adrian Bece

Posted on • Updated on

Revealing Module Pattern in JavaScript

After taking a short break during the holidays, I'm happy to be back with a new post. This time, we'll be taking a look at a Revealing Module Pattern, frequently used by JavaScript developers.

It's a very useful pattern that keeps our codebase clean and prevents malicious JavaScript manipulation from the browser console. Both junior and senior JavaScript developers are not usually aware of this pattern and it can be really useful for both performance and security.

I'm very fond of this pattern and I'm using it all the time when working on non-React projects.

About the window object

JavaScript's window object represents the browser window. Sounds simple enough. Like any object, it contains properties (variables) and methods (functions).

For example, some of the window properties are:

window.innerHeight - inner height of the browser window
window.innerWidth - inner width of the browser window

And some of the window methods are:
window.alert() - opens a popup window with a message
window.open() - opens a new window
window.close() - closes the current window

What's special about the window object is that it's globally accessible in most cases. Properties and methods of the objects can be accessed from any file that supports client-side JavaScript... and they can be accessed even from your regular browser via the dev tools.

Alt Text

Try running some of those commands

Potential issues with the window object

Malicious code manipulation

Try defining a JavaScript file that contains only the following line:

let score = 0;

const updateScore = (newScore) => score = newScore;
Enter fullscreen mode Exit fullscreen mode

It looks like a regular JavaScript, right? No apparent issues can be seen.

If you open this website in your browser, you can see the score variable included in the window object. Meaning that you can freely manipulate the variable directly from dev tools in your browser! If this variable is crucial to the site's functionality or it contains sensitive information, it can be easily accessed and exploited.

Alt Text

Uh oh...

The same rule applies to methods (function). Any function present in the window object can be called from the dev tools.

Performance & Garbage collection

You might have come across the advice along the lines of: Avoid polluting the global namespace. This basically means that we should avoid declaring global variables and functions. What is the reason for that?

Garbage collection means that the browser automatically manages memory by deciding which resources are needed at that moment. When a function or a variable is no longer needed, the browser frees up space. If all our variables and functions are part of a global window object, the browser automatically assumes that these are needed as long as the window (or a tab) is opened, so they will never be removed. The memory will always be allocated for those resources regardless of the fact if they are actually used. That is why we refer to this as garbage and pollution in terms of the code.

Public and private scope

Javascript doesn't really have the usual public or private scope modifiers like the regular Object-oriented languages do. We can solve this in a really elegant and simple way by using JavaScript's regular function-level scoping.

Revealing module pattern

This is where Revealing module pattern Javascript comes in. Let's take a look at the following example.

const game = (() => {
 let score = 0;

 const setScore = (newScore) => score = newScore;

 const incrementScore = () => setScore(score + 1);

 return {
  incrementScore
 }
})();
Enter fullscreen mode Exit fullscreen mode

We can see how Revealing module pattern lives up to its name.

const example = (() => {
  /* Variable and function definitions */

  return {
    /* Variables and functions that we would like to expose */
  }

})();
Enter fullscreen mode Exit fullscreen mode

All variables and functions that are not returned are considered private and cannot be accessed outside the scope of the function.

By returning an object that can contain any variables and functions declared in the IIFE (immediately-invoked function expression, which is explained later) we are choosing what parts of the functionality to reveal. These cannot be altered from the global scope. In a worst-case scenario, manipulation would cause the functionality to fail and the site would break on the client's side, but that is also true for any other kind of code manipulation that we can do from our browser's dev tools (HTML, CSS or JavaScript manipulation).

In our example, we have the following private elements:

  • score - a variable that keeps track of the current score value
  • setScore - a function that directly manipulates the score variable by setting its value directly. Also known as a setter function.

Those two functionalities are very important in our example and should not be accessed outside the function, so we need a create an interface that we can reveal that will update the score variable indirectly.

This is where the incrementScore function comes in. It only calls the private function and determines how the score should be incremented. Thusly, this functionality cannot be altered or manipulated in a malicious way beyond simply breaking the website on the client's side.

And, finally, by wrapping our game expression in the IIFE (immediately-invoked function expression), we prevent the function from being included in the window object and we avoid the possibility of someone to initialize another game from dev tools.

Now that we understand how Revealing Module Pattern works and how it can be implemented, let's go through an example.

Example

Let's imagine that we are working on a game and our task is to create a score tracking function that has the following functionality:

  • Initialize the score tracking with value of 0
  • Allows us to increment the score by 1 (rule of the game)
  • Resets the score
  • Submits the current score once the game is finished
  • Displays score state in HTML

window object implementation

Let's first implement this in a "regular way" just to get a better grasp of the functions and highlight the potential issues that we've explained.

Note: You might want to open this codepen link in a window to use the Console functionality in order to try and manipulate the score.

Let's see if we are able to manipulate the score from the browser's dev tools.

Alt Text

We have a full access to the variables and functions

As expected, we can easily access and manipulate the score value and call any function that we want.

Revealing module pattern implementation

Let's convert our JavaScript implementation into a Revealing module pattern. We can easily determine which parts of the interface need to be revealed by looking at which functions are being directly called from the HTML.

Let's see if we are now able to manipulate the score from the browser's dev tools.

Alt Text

As expected, score variable and the setter function is no longer the part of the global object

We have successfully removed our functionality and variables from the window object and we've prevented the possibility of manipulating the values in a malicious way.

We could have also taken a look into how to better protect the incrementScore function so the user cannot call it from the dev tools, but that would make this example a bit more complex than it needs to be. Also, this function is only revealed so it can be connected to a button for convenience. We could imagine that this would be tied into game mechanics which would also remain private functions.


These articles are fueled by coffee. So if you enjoy my work and found it useful, consider buying me a coffee! I would really appreciate it.

Buy Me A Coffee

Thank you for taking the time to read this post. If you've found this useful, please give it a ❤️ or 🦄, share and comment.

Top comments (1)

Collapse
 
noctap0d profile image
Victoria Rodriguez

Thank you! This was super useful. I specially love the inclusion of both examples, it helps me a lot.