The module pattern (in a nutshell) (original) (raw)

The module pattern (first publicized by the Yahoo! JavaScript team) makes use of closures to bake privacy and state into your objects.

This is the generic form…

function() { //private state //private functions return { //public state //public variables } }

Now lets put some meat on the bones. Here is a poll manager responsible for tallying yes and no votes:-

var pollManager = function() { //private state var alreadyVoted = {}; var yesVotes = 0; var noVotes = 0;

//return public interface
return {
    vote : function(name, voteYes) {
        if (alreadyVoted[name]) {
            alert(name + ", you can't vote twice");
        } else {
            alreadyVoted[name] = true;
            voteYes ? yesVotes++ : noVotes++;
        }
    },

    reportTally : function() {
        var results = [];
        results.push("Yes = ");results.push(yesVotes);
        results.push(", No = ");results.push(noVotes);
        return results.join("");
    }
}

}

var doYouLikeBroccoli = pollManager(); doYouLikeBroccoli.vote("Bob",true); doYouLikeBroccoli.vote("Mary",false); doYouLikeBroccoli.vote("Bob",true); //Bob, you can't vote twice doYouLikeBroccoli.reportTally(); //"Yes = 1, No = 1"

We could have written this as an object literal ({}), but by enclosing it in a function instead we created a closure. This has the effect of protecting state (and potentially functionality) from the outside world. We return only the public API, everything else is private – the names of voters cannot be listed, the vote tallies can only be updated by voting.

We can further crank up the privacy by rewriting the reportTally function to show only the percentages. We’ll also create a helper function called asPercentage. Since asPercentage is only useful within this module we won’t return it as part of the public API – which means it becomes a private function – the module now hides function access as well as state.

var pollManager = function() { //private state //... var asPercentage = function(value) { return Math.round((100*(value/(yesVotes + noVotes)))); }

//return public interface
return {
    //...
    reportTally : function() {
        return "Yes = " + asPercentage(yesVotes) + "%" +
            ", No = " + asPercentage(noVotes) + "%";
    }
}

}

//... doYouLikeBroccoli.reportTally(); //"Yes = 50%, No = 50%"

At the risk of stating the obvious, in JavaScript when you make a function private, the logic is not hidden. You won’t keep your encryption function a secret by hiding it in a module. The concept of privacy is restricted to runtime access. I can only invoke pollManager’s asPercentage function or retrieve the value of the noVotes variable from within the pollManager closure.

An equally important benefit of modules is tidiness. Private objects only exist for the lifetime of the module function call – after which they are available for garbage collection. Similarly, the module returns an API object (e.g. doYouLikeBroccoli) whose properties are functions (vote and reportTally). These function objects live and die with the API object.

Sometimes you might want to access part the publicly returned object from within your private methods. (For sometimes read very occasionally – I couldn’t really think of a convincing example that wouldn’t work better with this behavior factored out) . In that case we can assign the public object to a variable (addressable from anywhere in the function) before returning it.

function() { //private state //private functions (can refer to publicObj) var publicObj = {/...public API.../}; return publicObj; }

More often than not you will see modules wrapped in parentheses and invoked immediately to provide singletons. Churning out a large number of module instances would be clunky and inefficient but the implication that you would never ever need more than one polling manager or id generator in your app is a bit of a mystery to me.

I’m drawn to the module pattern for its elegance (and genius). You get to keep your code tidy by hiding the one-off grunt work in a box while highlighting the interface you intend others to interact with. Clearly stated intention is the bedrock of good programming.

So why don’t I use it very often? There are some obvious answers: most of the tidiness of this pattern can be replicated with a simple object literal pattern, prototyping is more efficient for multiple instance creation and most grunt work is not one-off…you want to put in a utility file and re-use it.

But there are also more subtle reasons: privacy and form are probably overrated in Javascript where there is no formal concept of interface, class or strong typing. Objects can be effortlessly reshaped and transformed and this is liberating, especially for those brought up on the rigid constructs of Java et al. Hiding and partitioning introduces unfamiliar constraints to JavaScript developers who generally rely on self discipline over enforced discipline.