Question

I'm understanding the principle of module pattern but when I look at the different definition I struggle to understand how anonymous functions work. In particular, takes those three examples

Example 1, (from http://viralpatel.net/blogs/javascript-module-pattern/)

CalcModule = (function(){
                var pub = {};
                pub.add = function(a, b) {
                             console.log('in add()', a, b);
                             return a + b;
                };
                pub.sub = function(a, b) {
                             console.log('in sub()', a, b);
                             return a - b;
                };
                return pub;
})();

which is used as

CalcModule.add(5,2) //returns : 7

Example 2 (from Learning JavaScript Design Patterns 1.5.2, Addy Osmani)

var testModule = (function () {

  var counter = 0;

  return {

    incrementCounter: function () {
      return counter++;
    },

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

which is used as

testModule.incrementCounter()

Example 3 (from http://css-tricks.com/how-do-you-structure-javascript-the-module-pattern-edition/)

var s,
NewsWidget = {

  settings: {
    numArticles: 5,
    articleList: $("#article-list"),
    moreButton: $("#more-button")
  },

  init: function() {
    // kick things off
    s = this.settings;
  }
};

which, by the way, I don't know ho to use it.

As you see, the methods, for example add, incrementCounter and init are defined in different ways:

  • Example 1: by means of a private variable pub
  • Example 2: in the return method!
  • Example 3: as method of the constructor NewsWidget

Question: In my mind Example 3 is what I would do and I don't understand why Example 1 and 2 are not used in the following way

  • Example 1: CalcModule.pub.add(5,2)
  • Example 2: no idea
Was it helpful?

Solution

It seems like you need to understand how return works in functions in order to understand why the provided examples behave the way they do.

Example 1: You create a new variable pub and adding two methods to it: add and sub. At the end, you're returning the pub variable to CalcModule

So when you call CalcModule, it returns the following object with two methods:

CalcModule = {
   add: function() {...},
   sub: function() {...}
}

Example 2: Let's rewrite example 2 similar to example 1...

var testModule = (function () {

  var counter = 0;
  var pub;

  pub.incrementCounter: function () {
      return counter++;
  }

  pub.resetCounter: function () {
      console.log( "counter value prior to reset: " + counter );
      counter = 0;
  }

  return pub;
})();

We know pub is an object...

pub = {
   incrementCounter: function() { ... },
   resetCounter: function() { ... }
}

and we're returning pub to testModule... therefore...

testModule = {
   incrementCounter: function() {...},
   resetCounter: function() {...}
}

Hope this is helpful.

OTHER TIPS

In example 1, pub is assigned to the variable CalcModule via the return statement and the assignment of the return value so CalcModule becomes an alias for pub directly. That's why it's CalcModule.add(). That value that is returned from the IIFE return pub; gets assigned to CalcModule. It's as if one did CalcModule = pub.

In example two, testModule is assigned an unnamed object via the return value and that object has the methods incrementCounter() and resetCounter(). So, again testModule becomes a named alias for that object so you can then refer to the methods in that object as testModule.incrementCounter() and testModule.resetCounter().

Example 1 as shown has no advantage over Example 3 so if you are more comfortable with Example 3, then that's fine. Your Example 3 has a variable s that seems a bit odd and out of character because you're setting a global variable when NewsWidget.init() is called which is usually not a good design pattern. Perhaps you want to return that value from .init().

Example 2 is using the IIFE (immediately invoked function expression) to create a safe and private place to store the counter variable that is not in the global namespace, cannot conflict with any other code and cannot be access by other code example your own methods. This is essentially a way to create a "private" variable that only your methods can access. Example 1 could have also used that capability, but your Example 3 does not have the option to use that capability because it doesn't have the enclosing IIFE.

The important part is to understand functions are first class citizen in JavaScript. Which means functions can be passed around and assigned to variables just like any other objects, so is modules.

In your first example, 2 functions (pub.add, pub.sub) as created as members of module pub, and then assigned to variable CalcModule

In second example, return variable is returning an object literal, which has two key/value pairs, with keys being function name and values being functions. assigning that object literal is equivalent to make the variable assigned as 2 member functions, which is creating namespace

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top