Question

Some articles (JavaScript Module Pattern In Depth, Mastering The Module Pattern) describe defining modules in JavaScript like in the snippet below (from Addy Osmani's "Learning JavaScript Design Patterns"):

var testModule = (function () {
    var counter = 0;
    return {
        incrementCounter: function () {
            return counter++;
        },
        resetCounter: function () {
           console.log( "counter value prior to reset: " + counter );
           counter = 0;
        }
    };
})();

Module usage:

testModule.incrementCounter();
testModule.resetCounter(); 

In this case we are using a single instance in the entire code, and it means that this module implementation is useful only if we want to create a singleton.

Is it true or there are other use cases when this Module pattern variation can be used?

Was it helpful?

Solution

I'd argue no-ish. I'm not sure it's really the "module pattern" if you return anything other than a singleton. But, you can certainly use the same "pattern" to accomplish other things.

The module protects the global scope from the internal variables used to build the return-value; but the return value can itself be a function -- including a constructor.

To that end, if you had a need for some sort of "private static" class member which you'd like all instances of a class to access, the module pattern can accomplish that.

As a silly example, suppose you're building a Counter class, wherein each individual Counter needs to track a certain event, but wherein you also want a protected TotalCountEvents across all Counter objects, you could do this:

var Counter = (function() {
  var totalcount = 0;

  var constructor = function() {
    var count = 0;
    this.increment = function() { count += 1; totalcount += 1; };
    this.getCount = function() { return count; };
  };

  constructor.getTotalCount = function() { return totalcount; };
  return constructor;
})();

You can then use it like this:

var counterA = new Counter();
var counterB = new Counter();

counterA.increment(); counterA.increment();
counterB.increment(); counterB.increment(); counterB.increment();

console.log(counterA.getCount(), counterB.getCount(), Counter.getTotalCount());

And you'll see:

> 2 3 5

But, access to the underlying totalcount will be restricted to instances of Counter.


Bear in mind, the factory pattern can accomplish the same sort of thing, just with stylistic/syntactic differences. Changing your factory to look like a "module" mostly allows you to create instances with new ... which is taboo in some circles anyway.

OTHER TIPS

You can return anything with the module pattern, it's just a way to avoid global pollution while instantiating a module. It's quite common to see it used to generate functions or constructors, which can then be used as often as needed:

var module = (function (){
    ...scoped stuff...

    return function () {
        ...do stuff with scoped stuff...
    };
}());

elsewhere:

var foo = new module();
var bar = new module(baz);
//or
var fizz = module(buzz);

A module is just an IIFE. If you want to reuse the function, then declare it as a function and reuse it to instantiate multiple modules:

function moduleFactory(...) {
  ...
  return {
    ...
  };
}
var module1 = moduleFactory(1);
var module2 = moduleFactory(2);

At this point you're no longer using the "module pattern", because it's not meant to handle multiple instantiation because an IIFE only returns one value (ignoring ES2015+ spread et all).

Licensed under: CC-BY-SA with attribution
scroll top