JavaScript Module Pattern

Shan Liu
3 min readOct 17, 2017

--

JavaScript Module Pattern is widely used in Node.js. To better understanding the concept, I read from articles and will also cite example here (in vanillaJS).

The Basics:

  • Anonymous Closures:

This is a simple an anonymous function, which execute immediately. All of the code that runs inside the function lives in a closure, which provides privacy and state throughout the lifetime of our application.

(function () {
// ... all vars and functions are in this scope only
// still maintains access to all globals
}());
  • Global Import

JavaScript has a feature known as implied globals. Whenever a name is used, the interpreter walks the scope chain backwards looking for a var statement for that name. If none is found, that variable is assumed to be global.

Luckily, our anonymous function provides an easy alternative.

(Also, we have “use strict” to avoid variable pollution)

(function ($, YAHOO) {
// now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));
  • Module Export

Sometimes you don’t just want to use globals, but you want to declare them. We can easily do this by exporting them, using the anonymous function’s return value.

var MODULE = (function () {
var my = {},
privateVariable = 1;

function privateMethod() {
// ...
}

my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};

return my;
}());

Notice that we’ve declared a global module named MODULE, with two public properties: a method named MODULE.moduleMethod and a variable named MODULE.moduleProperty. In addition, it maintains private internal stateusing the closure of the anonymous function. Also, we can easily import needed globals, using the pattern we learned above.

Advanced Patterns:

  • Augmentation

One limitation of the module pattern so far is that the entire module must be in one file. Anyone who has worked in a large code-base understands the value of splitting among multiple files. Luckily, we have a nice solution to augment modules.

First, we import the module, then we add properties, then we export it. Here’s an example, augmenting our MODULE from above:

var MODULE = (function (my) {
my.anotherMethod = function () {
// added method...
};

return my;
}(MODULE));

After this code has run, our module will have gained a new public method named MODULE.anotherMethod. This augmentation file will also maintain its own private internal state and imports.

  • Loose Augmentation

When argument is not always necessary, we can create flexible multi-part modules that can load themselves in any order with loose augmentation.

var MODULE = (function (my) {
// add capabilities...

return my;
}(MODULE || {}));
  • Cloning and Inheritance
var MODULE_TWO = (function (old) {
var my = {},
key;

for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}

var super_moduleMethod = old.moduleMethod;
my.moduleMethod = function () {
// override method on the clone, access to super through super_moduleMethod
};

return my;
}(MODULE));
  • Cross-File Private State
var MODULE = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};

// permanent access to _private, _seal, and _unseal

return my;
}(MODULE || {}));
  • Sub-modules
MODULE.sub = (function () {
var my = {};
// ...

return my;
}());

--

--