Hey, I'm writing a book too :) Click the link below to preorder and save ;)
»» Get the Only Reference You'll "ever" Need on JavaScript Engineering Interviews, Now! ««
April 24th in Module, Patterns and Practices, Tutorial by .

The JavaScript Module Pattern

Introduction

Module Pattern is excellent for encapsulating component-specific knowledge.
It was first coined by Eric Miraglia, years ago at Yahoo! User Interface Blog.

Especially when developing external widgets to sites, this pattern is a good candidate, because your widget’s logic will be encapsulated inside a closure, and it will not pollute the global namespace and it will not mess up the site’s global JavaScript code.

Although when used for non-singleton objects, using modules have some caveats to consider due to their static context, it’s a good practice to show love to the Module Pattern. (Likewise, we should show love to the object literal, but that’s the point of another discussion :) ).

You can click here, to get the source code of this tutorial (0.6K zipped archive) »»

Module Pattern with Anonymous Closures

In essence, a JavaScript module is nothing but a self-executing closure.

Let us start out with a simple anonymous closure:

(function () { 
    // module logic comes here. 
}());

This is the most basic module construct you can imagine: We simply create an anonymous function and execute it immediately. The closure provides a private static scope, hence a “module”. Each such module (closure) will have its own static context.

Caching Global Variables

It’s a good practice to cache commonly used global objects into our module’s scope. This will both increase performance and enable us extend our module by augmenting or overriding method definitions. Let’s see how:

(function(o2, window, undefined){
	// now you can access globals o2, window, and undefined.
}(o2, this));

jQuery, an ealy-adopter evangelizing the Module Pattern, clearly demonstrates this in its source code:

(function( window, undefined ) {
...
var jQuery = (function() {
...
}());
...
}(window));

Caching globals increase performance.

Caching globals increase performance, because whenever a name is used in JavaScript, the JavaScript interpreter iterates the scope chain backwards looking for a var statement for that name. The closer the variable found in the scope chain, the faster the script executes.

Avoid Implicit Global Declerations

Moreover, if a definition is used in an assignment, and it does not exist in anywhere within the scope chain, a new global is created. Defining implicit globals will give you nightmares you have never dreamed of.

function localVariableTest(){
	//this is a local variable and it only lives within the scope of function "localVariableTest"
	var myVariable = 'local';
}

function implicitGlobalVariableTest(){
	//this variable is implicitly "global", it can be accessed anywhere in the application.
	//never use such a decleration.
	myVariable = 'local';
}

Using impled globals is a big “no no”. Douglas Crockford‘s JavaScript quality tool JSLint, throws an error whenever it sees an implicit global variable decleration, for a good reason ;) It’s also a good practice to use JSLint to sanitize your JavaScript code.

In shourt, passing commonly used globals into an anonymous closure as function parameters is both cleaner and faster than using implied globals.

Encapsulation and Scoping in Modules

Each module has its own private scope.

//define an o2 namespace if it does not exist.
if(!o2){var o2 = {};}
//define a tutorial namespace if it does not exist.
if(o2 && !o2.tutorial){ o2.tutorial = {}; }
//if our tutorial is already defined, exit immediately.
if(o2.tutorial.module){ throw 'Trying to override an existing "o2.tutorial.module" namespace'; }

o2.tutorial.module = (function(o2, window, undefined){
	var me = {};
	//you cannot reach this from outside the module.
	var privateVariable = 1;
	//you cannot reach this from outside the module.
	function privateMethod(){}
	
	me.publicStaticProperty = 1;
	me.publicMethod = function(){
		// do stuff.
	};
	
	return me;
}(o2, this));

The sample above is a complete and most general demonstration of the Module Pattern.

Note that, in the above code, o2.tutorial.module.publicStaticProperty and o2.tutorial.module.publicMethod are publicly accessible; while the internal logic of the module, i.e. privateVariable and privateMethod are not directly accessible.

Adding Methods to a Module

(function(me, o2, window, undefined){
	me.augmentedMethod = function(){};	
}(o2.tutorial.module, o2, this));

This construct will enable us augment methods and properties to our module, by passing the entire module (“me”) as a parameter to the closure.

This way, we can semantically split our module into separate files and load them asynchronously, which is not uncommon in large-scale web applications.

If you work with a large code-base, splitting the code into as many files as possible is invaluable ;) .

Method Overriding

We may want to change an existing method and enrich it with some new functionality.

(function(me, o2, window, undefined){
	var cachedMethod = me.augmentedMethod; 
	me.augmentedMethod = function(){
		cachedMethod();//execute the old function.
		//... add more magic here, possibly enhancing functionality.
	};
	
}(o2.tutorial.module, o2, this));

Besides, we can do this for each and every single item of the module:

(function(me, o2, window, undefined){
	var cache = {};
	
	for(var key in me){
		if(me.hasOwnProperty(key)){ cache[key] = me[key]; }
	}
	
	var superMethod = cache.method;
	
	me.method = function(){
		superMethod();
		//do other stuff.
	}
}(o2.tutorial.module, o2, this));

Sharing Private State

One big limitation of splitting a module across multiple files is that each file maintains its own private static state, and does not get access to the state of the other files.

Ben Cherry proposes a relatively complex solution to this. Though, it’s JavaScript, you know :) .
Honestly, if we know what we are doing, a single shared “state” variable will not hurt anyone ;) .

//file1.js
function(me, o2, window, undefined){
	//shared private context, use it responsibly.
	var state = {
			lorem:'ipsum',
			dolor:'sit';
	};
	
	me.state = me.state || {};
	
	for(var key in state){
		me.state[key] = state[key];
	}	
}(o2.tutorial.module, o2, this);

//file2.js
function(me, o2, window, undefined){
	//shared private context, use it responsibly.
	var state = {
			ispum:'amet',
			lorem:'dolorem'
	};
	
	me.state = me.state || {};
	
	for(var key in state){
		me.state[key] = state[key];
	}	
}(o2.tutorial.module, o2, this);

Performance Considerations

Contrary to popular belief, Module Pattern is good in terms of performance: If you accurately import globals into the closure, run time performance will not suffer at all.

Initialization time may be a bit slower due to introducing an extra scope with closures, but it’s a tradeoff that can be safely taken.

In addition, this pattern allows lazy-loading: Parts of the module can be separeted into files and they can be lazy-loaded when necessary, with script injection, which will load in parallel without blocking the rest of the web application. See Steve Soulder’s excellent explanation on the issue, for details.

I hope that this walkthrough helped you gain some insight into the Module Pattern.

Feel free to share your ideas and comments to add value :)

It's me: Volkan! Jack of all Trades, Samurai of JavaScript ;) Since 2003, I’ve been doing front-end development on client-heavy AJAX web applications. Currently, I'm a JavaScript Hacker at "SocialWire". Before that I was a VP of Technology at "GROU.PS", a well-known do-it-yourself social networking platform that allows people to come together and form interactive communities around a shared interest or affiliation. Before that, I was a JavaScript Engineer at "LiveGO", a globally known social mash-up. Before that, I was the CTO of a business network ("cember.net") which was acquired by Xing AG for around 4.2M Euros. See my linkedin profile to find more about me; I also share worth-following bits an pieces on twitter.

VIsit Volkan Özçelik's website

4 Comments

Leave a Reply





o2.js _
Fork Ribbon