Modular Design Patterns: Private, Privileged, and Protected Members in JavaScript

Share this article

In this article, I’ll be describing the structure and benefits of an extended modular design patterns, that includes four principal member types:

  • public: members that can be accessed from anywhere
  • private: members that can only be accessed from inside the object
  • privileged: members that can only be directly accessed from inside the object, but which can be indirectly accessed from outside via a public method
  • protected: members that can only be accessed from inside the object or any of its modules.
This article is not about object-orientation, because the structure we’re going to create is a kind of singleton, which is a single-instance structure that cannot be instantiated more than once. In fact, it isn’t instantiated at all (in the sense of having a constructor), so it’s an object-based rather than object-oriented pattern. For more about the difference between object-based and object-oriented programming, and an introduction to object-orientated programming in JavaScript, I’d recommend Ryan Frishberg’s article: JavaScript Object-Oriented Programming.

Modular Design Patterns

The basic design pattern I’ll be using here is the Revealing Module Pattern, which is a variation of the classic Module Pattern, but with more control. Although there are already quite a few articles that describe these patterns, very few take the time to actually explain how they work, and even fewer have such a complete set of features!

The Basic Module Pattern

The classic Module Pattern wraps all the code for a script in an anonymous function literal, which is assigned to a single variable when it returns. A function-literal is simply a function which calls itself, so the eventual assignment of a function-literal is not a function, it’s whatever value the function returns. To take a simple example, a function-literal encloses a calculation, and so the final value assigned to sum is the result of that calculation:
var sum = (function() { return 6 * 7; })();
To illustrate what that syntax means, here’s the same code abstracted into a named function:
function calculate() { return 6 * 7; }
var sum = (calculate)();
In that case we don’t actually need the brackets around calculate, but we do when using an anonymous function, so that it’s evaluated as a single expression without having to be pre-assigned.

Public and Private Members

So within the function-literal we can put any other code — such as variables, properties and functions — and it’s the different kinds of syntax used to define the internal data that determines the split between public and private members. Here’s an example:
var MyModule = (function() {
  var myPrivateData = 303;
  function myPrivateFunction() {
    alert('private');
  }
  return {
    myPublicData : 42,
    myPublicFunction : function() {
      alert('public');
    }
  };
})();
Since we returned an object of properties, and that’s assigned to MyModule, the properties can be accessed from outside the object as MyModule.myPublicData and MyModule.myPublicFunction. But we can’t access myPrivateData or myPrivateFunction at all, because variables are only accessible within their original scope. The scope of a variable is the context in which it’s defined, determined by using the var statement. In this example the scope of the private variables is the MyModule object, and therefore they can only be accessed from inside that object.

The Revealing Module Pattern

With the module pattern we’ve used two different kinds of syntax, to create the difference between public and private members. The Revealing Module Pattern is a variation of that, which allows us to use the same kind of syntax for all our internal constructs, only deferring to object-literal notation at the end, to return (or reveal) the public members. Let’s see that object again, but this time using the revealing module pattern:
var MyModule = (function() {
  var myPrivateData = 303;
  function myPrivateFunction() {
    alert('private');
  }
  var myPublicData = 42;
  function myPublicFunction() {
    alert('public');
  }
  return {
    myPublicData : myPublicData,
    myPublicFunction : myPublicFunction
  };
})();
The split between public and private members is still the same, but this time it’s implemented not by the original syntax used to define those members, but simply by what’s returned. This makes the revealing module pattern a useful variant, because it allows for an internally consistent style of coding. It also means you can change the names of public members when they’re returned, and even change at any time which members will be public at all. This pattern was innovated by Christian Heilmann, who provides an excellent explanation of it, and the module pattern it’s based on, in his article: Again with the Module Pattern — Reveal Something to the World.

The Benefits of Different Syntax

Sometimes though, a difference in syntax and coding style can be helpful, simply to remind yourself and others of which members are public or private. The syntax you use can be a kind of self-documentation, to indicate, for example, that functions declared using the function foo syntax will always be private. The kind of syntax you use for a function also affects the kind of syntax you can use inside it. In the example below, the use of this.foo syntax for the public function, means it can use the same syntax to refer to other public properties (if they’re also defined with that syntax). And if all the public members are defined with that same syntax, then all you eventually need to return is this:
var MyModule = (function() {
  var myPrivateData = 303;
  function myPrivateFunction() {
    alert('private');
  }
  this.myPublicData = 42;
  this.myPublicFunction = function() {
    alert(this.myPublicData);
  }
  return this;
})();
Now that isn’t a revealing module pattern any more, it’s just a normal module pattern with a different syntax. But it’s important to understand both patterns and their variations, because the final pattern I’m going to show you will be using features from all of them.

Adding Privileged Members

Although private members can only be accessed from inside the object, public members which refer to them can effectively make them public too. For example, a public function could return the value of a private variable, like this:
var MyModule = (function() {
  var myPrivateData = 303;
  this.myPublicFunction = function() {
    return myPrivateData;
  }
  return this;
})();
alert(MyModule.myPublicFunction()); //alerts 303
When a public function allows private data to be accessed from outside the object, this is known as privileged. In strict programming parlance it’s the function itself that’s privileged, but personally I find it much more helpful to think of the variables they access as the privileged ones; they’re the ones that are different. The private variable in question still can’t be directly accessed from outside the object, it only be indirectly accessed via the public function. This means the function can control what kind of access is allowed, as loosely or precisely as required. It might limit access to a maximum number of calls, for example, or parse the value before it’s returned for conversion or normalization; the example above allows the variable to be returned but not to be modified, but conversely, we might want it to be modified but not returned. For me, the most useful thing to do with privileged members is to use them for a library’s global configuration. For example, an animation library would have individual public methods, each with their own settings passed as arguments. But it could also have a configuration object that defines global settings, such as a resolution value that determines how coarse or fine the animations are. Using a privileged object we can validate any changes to those settings — for example, converting input values to numbers then rejecting those that fail:
var MyLibrary = (function() {
  var config = { resolution : 10 };
  this.define = function(key, value) {
    if(typeof config[key] == 'undefined') {
      alert('There is no config option "' + key + '"');
    } else {
        if(isNaN(value = parseInt(value, 10))) {
          alert('The value defined for "' + key + '" is not a number');
        } else {
          config[key] = value;
        }
    }
  };
  return this;
})();
MyLibrary.define('fail', 20); //alerts the first failure
MyLibrary.define('resolution', 'fail'); //alerts the second failure
MyLibrary.define('resolution', 20); //resolution is now 20
In this way, the config values are effectively shielded; since the library user can’t modify them directly, it’s impossible for them to inadvertently break the library’s functionality, by using settings that won’t work.

Creating Additional Modules

Now we’ve created a design pattern with public, private and privileged members. But remember that we’re calling it a module pattern, so it must be able to have additional modules in the same object context (ie, that share the same public data and have the same concept of this). There are several ways of achieving this, but the one I prefer is to use apply(). The apply method allows you to specify the object context in which a function is evaluated, effectively overriding the meaning of this. So to bind additional modules into the MyModule context, we simply modify the function-literal syntax to pass it through apply:
var MyModule = (function() {
  this.version = '1.0';
  return this;
})();
var MyModule = (function() {
  this.getVersion = function() {
    return this.version;
  };
  return this;
}).apply(MyModule);
alert(MyModule.getVersion()); //alerts "1.0"
Binding additional modules in this way is sometimes known as augmentation. You might also hear it described as strict augmentation or loose augmentation — where strict augmentation means the modules must load in synchronous order, as opposed to loose augmentation where they can load in any order. (Normal <script> tags load their content in synchronous source-order, whereas dynamically generated scripts that are added later will load asynchronously.) In my experience, it’s rare for an application to be able to work with loose augmentation. Modules inevitably have dependencies on one another, and therefore have to load in a specific order. Our examples are all like this.

Adding Protected Members

Splitting a script into multiple modules is a common and convenient practice. It makes a large codebase much easier to manage, and allows for bandwidth savings to be made when modules aren’t always required. But what if we want to share data between different modules? If we make that data public then we’ll lose the benefits of privacy, but if we make it private it will only be available to one module. What we really need are shared private members, and these are known as protected. JavaScript doesn’t have protected members as such, but we can effectively create them by making data temporarily public. To achieve this, let me first introduce you to two key functions — extend and privatise — which we’ll define as part of a utility-functions object:
var utils = {
  extend : function(root, props) {
    for(var key in props) {
      if(props.hasOwnProperty(key)) {
        root[key] = props[key];
      }
    } return root;
  },
  privatise : function(root, prop) {
    var data = root[prop];
    try { delete root[prop]; } catch(ex) { root[prop] = null; }
    return data;
  }
};
The extend function simply adds new properties to an object, while the privatise function
copies a property and then deletes the original. We can use extend in one module to create a public reference to a private variable, and then use privatise in another module to copy it back to a private variable and delete the public reference. So here’s an example of the first module which has two protected members (including the utils object itself), and one public member. To keep the code example short, the utility functions are just empty shells, but they would be identical to the functions I showed you a moment ago:
var MyModule = (function() {
  var myProtectedData = 909;
  var utils = {
    extend : function(root, props) { },
    privatise : function(root, prop) { }
  };
  this.myPublicData = 42;
  return utils.extend(this, { myProtectedData : myProtectedData, utils : utils });
})();
You can see how we’re using a variant of the revealing module pattern, to return not just the public members, but the protected members as well. So at this point we have three public members: MyModule.myProtectedData, MyModule.utils and MyModule.myPublicData. Now here’s an example of the last module which uses the privatise function to copy the specified public members back to private variables, and then delete their public references:
var MyModule = (function() {
  var myProtectedData = this.utils.privatise(this, 'myProtectedData');
  var utils = this.utils.privatise(this, 'utils');
  return this;
}).apply(MyModule);
And once that’s done the protected members are locked inside their objects, privately available to both the modules, but no longer available from outside them.

Note that the privatise function relies on having separate arguments for the object and the property-key, because objects in JavaScript are passed by reference. So root is a reference to MyModule, and when we delete a property from it that’s specified by key, we’re deleting that property from the referenced object.

But if it was like this:
privatise : function(root) {
  var data = root;
  try { delete root; } catch(ex) { root = null; } return data;
}
And called like this:
var myProtectedData = this.utils.privatise(this.myProtectedData);
Then the public members would not be deleted — the function would simply delete the reference, not the property it refers to. The try ... catch construct is also necessary for older IE versions, in which delete is not supported. In that case we nullify the public property rather than deleting it, which is obviously not the same, but has an equivalent end result of negating the member’s public reference.

Extending Protected Members

With that framework in place we can add any number of additional modules, and have them all share the protected members, simply by adding them between the first and last modules. In these intervening modules the members are not privatised, they’re simply passed through:
var MyModule = (function() {
  var myProtectedData = this.myProtectedData;
  var utils = this.utils;
  return this;
}).apply(MyModule);
In fact, it isn’t strictly necessary to copy the protected members to private variables at all, but doing so means we have a consistent form of reference in every module. We can also extend protected objects on a module-specific basis, for example, to define additional utility functions that only certain modules need. Such extensions will obviously also be available to later modules:
var MyModule = (function() {
  var myProtectedData = this.myProtectedData;
  var utils = this.utils.extend(this.utils, { extraStuff : function() { } });
  return this;
}).apply(MyModule);
One final thing to note is that protected members can also be privileged. The example I showed you earlier, of a privileged config object, is a prime candidate for data that could usefully be protected. The end result would be configuration settings that all the modules can use, but that the user still can’t modify without going through the public define function.

The Final Extended Module Pattern

I’ve prepared a download file that includes all the features covered in this article, and is split into three separate files: Master.js is the root object that declares the original members, Extension.js is the optional intervening module (of which any number of instances can be used), then Runtime.js is the final module that seals the protected members:

Frequently Asked Questions about Modular Design Patterns in JavaScript

What are the benefits of using modular design patterns in JavaScript?

Modular design patterns in JavaScript offer several benefits. Firstly, they help in organizing code into distinct, independent sections known as modules. This makes the code easier to manage, understand, and debug. Secondly, they promote code reusability. You can create a module once and reuse it across different parts of your application, reducing redundancy and improving efficiency. Thirdly, they provide a way to encapsulate private data. In JavaScript, encapsulation is not built-in, but with modules, you can create private variables and methods that are inaccessible from outside the module.

How does the module pattern differ from other design patterns in JavaScript?

The module pattern differs from other design patterns in JavaScript in its emphasis on encapsulation and organization. While other patterns like the prototype or observer patterns focus on object creation or event handling, the module pattern is all about structuring your code in a way that promotes reusability and data privacy. It’s a way to create self-contained pieces of code that can be plugged into different parts of your application without causing conflicts or dependencies.

Can you explain the concept of closures in relation to the module pattern?

Closures are a fundamental concept in JavaScript that are crucial to the module pattern. A closure is a function that has access to its own scope, the outer function’s scope, and the global scope. In the context of the module pattern, closures allow us to create private variables and methods. When we create a function inside a module, that function has access to the module’s scope, which includes any variables or methods defined in the module. However, those variables and methods are not accessible from outside the module, effectively making them private.

How can I use the module pattern to create private variables and methods?

To create private variables and methods using the module pattern, you simply define them inside the module. Here’s an example:

var myModule = (function() {
var privateVar = 'I am private';
var privateMethod = function() {
console.log(privateVar);
};

return {
publicMethod: function() {
privateMethod();
}
};
})();

myModule.publicMethod(); // logs 'I am private'

In this example, privateVar and privateMethod are not accessible from outside myModule. However, they can be accessed by publicMethod, which is exposed to the outside world.

What are the drawbacks of using the module pattern in JavaScript?

While the module pattern offers many benefits, it also has a few drawbacks. One of the main drawbacks is that it can lead to more complex code. Because modules are self-contained, they need to provide their own methods for everything they need to do, which can lead to code duplication if not managed carefully. Additionally, because private variables and methods are not accessible from outside the module, testing can be more difficult. Finally, the module pattern can lead to more memory usage, as each module has its own private scope.

How does the module pattern support code reusability?

The module pattern supports code reusability by allowing you to create self-contained pieces of code that can be used in different parts of your application. Each module can be thought of as a plug-and-play component that provides a specific functionality. You can create a module once and then reuse it wherever that functionality is needed. This not only reduces redundancy but also makes your code easier to manage and debug.

Can I use the module pattern with other design patterns in JavaScript?

Yes, the module pattern can be used in conjunction with other design patterns in JavaScript. In fact, it’s common to use multiple patterns together to solve complex problems. For example, you might use the module pattern to structure your code and the observer pattern to handle events. The key is to understand the strengths and weaknesses of each pattern and choose the right one for the task at hand.

How does the module pattern help in managing dependencies in JavaScript?

The module pattern helps in managing dependencies by encapsulating related code into self-contained modules. Each module can specify its own dependencies, making it clear what other modules or libraries it relies on. This makes it easier to manage and update dependencies, as you can see at a glance what each module needs to function correctly.

Can I use the module pattern in both client-side and server-side JavaScript?

Yes, the module pattern can be used in both client-side and server-side JavaScript. On the client side, it can help manage complexity in large web applications by organizing code into modules. On the server side, it can be used to structure Node.js applications, where modules are a fundamental part of the ecosystem.

How does the module pattern relate to modern JavaScript frameworks like React or Angular?

Modern JavaScript frameworks like React and Angular have their own ways of managing code structure and dependencies, but the principles of the module pattern are still relevant. These frameworks encourage the use of components, which are similar to modules in that they are self-contained pieces of code. Understanding the module pattern can help you better understand and use these frameworks.

James EdwardsJames Edwards
View Author

James is a freelance web developer based in the UK, specialising in JavaScript application development and building accessible websites. With more than a decade's professional experience, he is a published author, a frequent blogger and speaker, and an outspoken advocate of standards-based development.

Intermediate
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week