Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Using the Revealing Module Pattern in Javascript

The Revealing Module Pattern in Javascript

Zach Caceres

Javascript does not have the typical 'private' and 'public' specifiers of more traditional object oriented languages like C# or Java. However, you can achieve the same effect through the clever application of Javascript's function-level scoping. The Revealing Module pattern is a design pattern for Javascript applications that elegantly solves this problem.

The central principle of the Revealing Module pattern is that all functionality and variables should be hidden unless deliberately exposed.

Let's imagine we have a music application where a musicPlayer.js file handles much of our user's experience. We need to access some methods, but shouldn't be able to mess with other methods or variables.

Using Function Scope to Create Public and Private Methods

Let's first see how Javascript's function-level scope can help us create public and private methods.

We can move all functionality inside a function's scope. Then we return an object with the functions that we'd like accessible in other files.

// musicPlayerModule.js

var musicPlayer = function () {
  // Let's make sure no one can directly access our songList
  var songList = ['California Girls', 'California Dreaming', 'Hotel California'];  

  // We'll expose all these functions to the user
  function play () {
    console.log('Im playing the next song!');
  }

  function pause () {
    console.log('Im paused!');
  }

  function addTrackToMusicQueue (track) {
    songList.push(track);
    console.log('I added a song');
  }

  function showNextTrack () {
    console.log('My next track is', songList[0]);
  }

  // Let's hide this function
  function loadSong() {
    filesystem.loadNextSong();
  }

  return {
    playMusic: play,
    pauseMusic: pause,
    showNextTrack: showNextTrack,
    addTrack: addTrackToMusicQueue
  }
}

const musicModule = musicPlayer(); // invoke our musicPlayer to return it's object (module)
musicModule.playMusic(); // 'Im playing the next song!'
musicModule.pauseMusic(); // 'I'm paused!'
musicModule.showNextTrack(); // 'The next track is California Girls'

// Things we can't access...
musicModule.loadSong(); // error: not a function
musicModule.songList.push('White Rabbit'); // undefined error

Now we can access all the methods that we need on our musicModule object. But we can't fiddle with our songList or access the loadSong() method. These are both private.

This works fine. But there's one big problem.

We're using musicPlayer as a namespace to hold our functions. But wait, our musicPlayer is a function that's still exposed to the global scope!

Someone could come along and invoke it again, creating a new musicPlayer. Then we would have multiple instances of musicPlayer floating around, polluting our environment and causing all sorts of confusion.

Hiding Your Module with an IIFE

The best way to avoid exposing your top-level function to the global scope is to wrap everything in an IFFE. An IIFE is an immediately-invoked function expression. That's a mouthful. It just means that we call (invoke) this function as soon as the file is run (immediately).

Since our function has no name, we call it an expression. Since it has no name, it can never be invoked elsewhere.

Here's how that looks:

var musicModule = (function () {
  // Let's make sure no one can directly access our songList
  var songList = ['California Girls', 'California Dreaming', 'Hotel California'];  

  // We'll expose all these functions to the user
  function play () {
    console.log('Im playing the next song!');
  }

  function pause () {
    console.log('Im paused!');
  }

  function addTrackToMusicQueue (track) {
    songList.push(track);
    console.log('I added a song');
  }

  function showNextTrack () {
    console.log('My next track is', songList[0]);
  }

  // Let's hide this function
  function loadSong() {
    filesystem.loadNextSong();
  }

  return {
    playMusic: play,
    pauseMusic: pause,
    showUpNext: showNextTrack,
    addTrack: addTrackToMusicQueue
  }
})(); // our IIFE function (surrounded with parens) is invoked here

musicModule.playMusic(); // 'Im playing the next song!'
musicModule.pauseMusic(); // 'I'm paused!'
musicModule.showUpNext(); // 'The next track is California Girls'
musicModule.loadSong(); // error: not a function
musicModule.songList.push('White Rabbit'); // undefined

Our function-level scope still keeps our methods and variables public and private based on whether we expose them in the return object.

But this time, we avoid the risk that we can invoke our module elsewhere in the code.

In other files we can now use musicModule's' functionality – a well-encapsulated module in our global scope!

@victorighalo

This comment has been minimized.

Copy link

@victorighalo victorighalo commented Sep 21, 2019

This is a Very lucid explanation. I am just learning about this pattern. Thanks.

@tranhducvnn

This comment has been minimized.

Copy link

@tranhducvnn tranhducvnn commented Oct 2, 2019

Great explanation. I have learned new knowledge from this. Thanks.

@Calebyang93

This comment has been minimized.

Copy link

@Calebyang93 Calebyang93 commented Nov 5, 2019

Great explanation. Thanks for sharng! learnt a lot.

@jetjokers24895

This comment has been minimized.

Copy link

@jetjokers24895 jetjokers24895 commented Jan 9, 2020

Thanks you very much!. This is very good for me!

@nakulvijay56

This comment has been minimized.

Copy link

@nakulvijay56 nakulvijay56 commented Feb 25, 2020

Nice explanation, but can someone give the advantage and the disadvantage of using this design pattern. I am just learning this pattern.

@chirag97

This comment has been minimized.

Copy link

@chirag97 chirag97 commented Apr 7, 2020

thanks for the subtle and to the point explaination.

@Hoxtygen

This comment has been minimized.

Copy link

@Hoxtygen Hoxtygen commented Apr 17, 2020

Thanks for this piece @zcaceres
Is this a typo The best way to avoid exposing your top-level function to the global scope is to wrap everything in an **IFFE**

@NelzkieCoder

This comment has been minimized.

Copy link

@NelzkieCoder NelzkieCoder commented Jun 29, 2020

Thanks

@isam123

This comment has been minimized.

Copy link

@isam123 isam123 commented Jul 2, 2020

Thanks Man

@akihshen

This comment has been minimized.

Copy link

@akihshen akihshen commented Jul 5, 2020

Thanks

@jdiegosierra

This comment has been minimized.

Copy link

@jdiegosierra jdiegosierra commented Aug 21, 2020

I don't understand the advantage of using Hiding Your Module with an IIFE. Can someone show me a code example with the problem?

@omundy

This comment has been minimized.

Copy link

@omundy omundy commented Sep 17, 2020

Where would you place "use strict"; if using several modules? Inside or outside?

@tiomno

This comment has been minimized.

Copy link

@tiomno tiomno commented Oct 29, 2020

Thanks, neat explanation!

@jdiegosierra, I was playing with this pattern and came up with a rather contrived example, but you can get the idea. Check out the comments. ;)

Revealing Module Pattern without IIFE

Revealing Module Pattern with IIFE

Hope it helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment