Reputation: 713
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:
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
Upvotes: 0
Views: 2161
Reputation: 743
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.
Upvotes: 2
Reputation: 1097
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
Upvotes: 0
Reputation: 707456
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.
Upvotes: 0