This is called a "factory function", it creates a "safe" lexical scope, meaning that the variables contained within the function cannot be altered or otherwise accessed from the global scope.
Every call to the factory function (every instance of private()
in your code) invokes the factory function again, creating a new scope. When you assign the returned value of private()
it saves the returned object, and its access to the lexical scope in which it was created, to that variable.
Using the Immediately Invoked Function Expression syntax (hereafter referred to as IIFE) we can expand the examples to show what is happening.
The first example:
private().add(5);
private().retrieve();
is expanded as follows:
(function(){
var counter = 0;
return {
add: function(increment) { counter += increment},
retrieve: function() { console.log('the counter is currently set to ' + counter)}
};
})().add(5);
(function(){
var counter = 0;
return {
add: function(increment) { counter += increment},
retrieve: function() { console.log('the counter is currently set to ' + counter)}
};
})().retrieve();
While the second example:
var p = private();
p.add(5);
p.retrieve();
is expanded as follows:
var p = (function(){
var counter = 0;
return {
add: function(increment) { counter += increment},
retrieve: function() { console.log('the counter is currently set to ' + counter)}
};
})();
p.add(5);
p.retrieve();
That is why the first example does not provide the expected output, and the second example does.
So, if you only want one safe scope, and you won't need to create a new scope later on, an IIFE will suffice.
var private = (function() {
var counter = 0;
return {
add: function(increment) { counter += increment},
retrieve: function() { console.log('the counter is currently set to ' + counter)}
}
})();
private.add(5);
private.retrieve(); // the counter is currently set to 5
private.add(5);
private.retrieve(); // the counter is currently set to 10