Yeah you pretty much got the idea of the difference between the two, let's look at why you might want one over the other.
An IIFE is useful to isolate the scope. It lets you keep the variables you define private inside the IIFE without polluting the global space around it. It's a nice way to compose a function that has some variables you don't need lurking around. Let's minimize this example a bit.
var Counter = (function () {
var count = 0;
var counter = {
add: function () {
count++;
},
subtract: function () {
count--;
},
getCount: function () {
return count;
}
}
return counter;
})();
Counter.add();
Counter.add();
Counter.getCount(); // 2
Counter.subtract();
Counter.getCount(); // 1
What happens above is that we're able to compose this "counter" functionality without leaking the private information, like count
. It'd be bad if other things could override it by accident. Also what happens is that right away we can assign Counter
to the result of the IFFE -- the counter
set of functions. Counter
is now equal to that, and counter
is able to retain access to count
since it was defined in the same scope.
The benefit here is that we're able to assign a variable to this composition of functionality. The IIFE basically allows us to immediately return what we return
inside of it. Since we assign Counter
to the IIFE, and the IIFE returns the functionality inside of it, Counter
is now a fully functional component.
We don't always have to use IIFE. It's really handy when you want to "tuck away" the implementation details and return an API.
So, what if we had the same thing, but it wasn't an IIFE -- just a function?
Just like your example, we'd have to call it in order to get the "instance".
var CounterFactory = function () {
var count = 0;
var counter = {
add: //...
subtract: //...
getCount: //...
};
return counter;
};
var CounterA = CounterFactory();
var CounterB = CounterFactory();
CounterA.add();
CounterA.add();
CounterA.getCount(); // 2
CounterB.add();
CounterB.getCount(); // 1
See the difference? It's all about what the function is returning. In the first example we only get a single Counter
instance, which may be perfectly fine. In the second example, it's more of a "factory" -- it generates an instance of counter
and we can call that multiple times and get multiple instances of it.