7

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?

3

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.

  • Let's take your example and make some changes. For example, let's imagine that I need only individual Counter to track a certain event. I defined module using function declaration in this code snippet and then just use it as a constructor. Is it still Module pattern and if yes, is it appropriate way to create module like this or there are any disadvantages of this approach? – alinaish Feb 6 '16 at 20:31
  • @alinaish Nope, that's not the module pattern. It's just a vanilla constructor, which certainly allows private instance variables; but, that's not the point of the module pattern. The main characteristic of the module pattern, in my understanding, is an immediately-invoked function expression that returns a value, which allows you to keep everything you use in building the return-value (module) out of the global scope. – svidgen Feb 6 '16 at 20:48
  • With that said, I haven't read anything that specifically forbids the IIFE's return value from being a function/constructor. And, I tried to suggest in my answer above that, while doing so can come with some added treats, it's not really the primary purpose of the module pattern, which is to create a single return-object without leaving any other traces or "evidence" laying around the global or enclosing scope (like the module's constructor). – svidgen Feb 6 '16 at 20:51
0

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).

  • 1
    I think what the OP is asking is: how would you make multiple copies of a module? In other words, how do you treat the module as a class, and make multiple instances of it, each instance containing its own encapsulated state? – Robert Harvey Feb 5 '16 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.