2

I am trying to wrap my head around different Module pattern declinations. I see different ways of writing these modules and exposing their data.

I'm expecting information on advantages/disadvantages, better patterns not described here, use cases for each of them.


A) Object literal wrapped in a self invoking function, firing off with an init method: (source)

(function() {

var MyModule = {
  settings: {
    someProperty: 'value';
  }

  init: function() {
    someMethod();
  }

  someMethod: function() {
    // ...
  }
};

MyModule.init();
})();

This is an example of a simple "Tweet This" utility I built. Am I using this pattern correctly? So far it's the only one that I have actual experience in writing.


B) Module as a namespaced self-invoking anonymous function: (source)

var MyModule = (function () {
  var MyObj = {}

  function privateMethod() {
    // ...
  }

  MyObj.someProperty = 1;
  MyObj.moduleMethod = function () {
    // ...
  };

  return MyObj;
}());

Are there any advantages/disadvantages over the previous style? Also, what would be the implications of using object literal notation here instead of the dot syntax in the example? Object literal seems cleaner and easier, but I'm not really aware of the proper use cases for each?


C) Module as a namespaced self-invoking anonymous function, but only exposing desired results through a return block: (source)

var MyModule = (function() {
  var myPrivateVar, myPrivateMethod;

  myPrivateVar = 0;

  myPrivateMethod = function(foo) {
    console.log(foo);
  };

  return {
    myPublicVar: "foo",

    myPublicFunction: function(bar) {
      myPrivateVar++;
      myPrivateMethod(bar);
    }
  };

})();

Similar to the previous style, but instead of exposing an entire object with all of it's properties/methods, we're just exposing specific bits of data through a return statement.


D) Module as a function wrapped in a self-invoking anonymous function, with nested functions acting as methods. The module is exposed through the window object, then constructed via the new keyword: (source)

(function(window, undefined) {

  function MyModule() {

    this.myMethod = function myMethod() {
      // ...
    };

    this.myOtherMethod = function myOtherMethod() {
      // ...
    };

  }

  window.MyModule = MyModule;

})(window);

var myModule = new MyModule();
myModule.myMethod();
myModule.myOtherMethod();

I'm assuming the strength of this pattern is if the module is a 'template' of sorts where multiple entities may need to exist within an application. Any specific examples of a good use case for this?

2
  • 1
    You should check out the book Javascript Design Patterns by Addy Osmani. Its a great intro into this topic for beginners. You can read it for free here addyosmani.com/resources/essentialjsdesignpatterns/book Commented Mar 7, 2016 at 19:34
  • 1
    this is a really broad question... Commented Mar 7, 2016 at 19:42

1 Answer 1

2

All of these are using the same pattern just in slightly different ways.

A) Object literal wrapped in a self invoking function, firing off with an init method:

This is fine if you don't intend to allow anyone else to access a chunk of code. You don't even have to have an init function. Wrapping your code in an IIFE (immediately invoked function expression) prevents global namespace pollution and allows the use of "private" variables. In my opinion, this is just good practice, not a module.

B) Module as a namespaced self-invoking anonymous function:

This is what people mean when they're talking about the module pattern. It gives you private variables and functions then exposes those through a public interface. That interface just so happens to be called MyObj in your example.

C) Module as a namespaced self-invoking anonymous function, but only exposing desired results through a return block:

This is actually exactly the same thing a B. The only difference is that methods on the interface can't directly reference the interface itself like you can in B. Example:

MyObj.methodA = function() {
  return MyObj.methodB();
};

That will work with the previous example because you have a name to reference it but is only useful when you expect public methods to be called using anything other than the returned object as the execution context. i.e, setTimeout(MyModule.methodA) (that will be called with the global context so this.methodB() would not work as intended.

D) Module as a function wrapped in a self-invoking anonymous function, with nested functions acting as methods. The module is exposed through the window object, then constructed via the new keyword:

Same thing as the previous 2 except for 2 minor differences. window is passed as an argument because it has historically been true that it's faster to access a local variable than a global variable because the engine doesn't have to climb up the scope chain. However, most JS engines these days optimize accessing window since it's common and a known object. Likewise, undefined is given as a parameter with nothing passed as an argument. This ensures you have a correct undefined value. The reasoning behind this is that technically, you can assign any value to undefined in non-strict mode. Meaning some 3rd party could write undefined = true; and suddenly all of your undefined checks are failing.

The other difference is that you're returning a function instead of an object. The bonus behind this is that you can have private variables which are shared in each instance of an object, as well as private variables per instance. Example:

var count = 0;
function MyObject(id) {
  var myID = id;
  count++;

  // Private ID
  this.getID = function() {
    return myID;
  };

  // Number of instances that have been created
  this.getCount = function() {
    return count;
  };
}

The downside to this is that you aren't attaching methods to the prototype. This means that the JS engine has to create a brand new function for every single instance of the object. If it was on the prototype, all instances would share the same functions but could not have individual private variables.

Sign up to request clarification or add additional context in comments.

1 Comment

Strong explanation that has cleared up a lot of details I was missing — thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.