A blog for technology, SEO tips, website development and open source programming.

The Module Pattern in JavaScript

0 858

 

Have you ever wondered how some of those huge JavaScript projects out there are getting built?

This is done using “Module Patterns”.The post will cover a couple of these patterns that are useful for any developer and can be easily adopted, maintain and build to any project. Firstly, we will learn how to use the module pattern in javascript and what are the benefits of using it on any project.  Then we will talk about underscore toolkit, benefits and usage of minification. Lastly we will talk about Module Export Pattern, sub-module and Loose Augmentation.

Let’s run an example

Every example I use in the post you can test it as well.

I use Google Chrome Developer Tools (Inspect Element-> Console)

function foo(){
console.log('helloworld');
};
foo();

foo variable is accessible in the global namespace.
This is what we refer to as cluttering the global namespace.  If the variables you created share the same name as the variables from another library this will end up disastrous because you will end up with lot’s of variable conflicts in your project.

Basic module pattern

In order to solve this we need to use basic module pattern. Nowadays,The module pattern is a common JavaScript coding pattern. In order to use the basic module pattern we need to wrap the code in a self executing anonymous function( a function without a name). Anonymous Functions stored in variables do not need function names. They are always invoked (called) using the variable name.

Cool, let’s now change our example code to use the pattern.

(function(){
function foo(){
console.log('helloworld');
};
foo();
}());

The function is now wrapped in closers(green colour marked) because the function itself without a name will return undefined. However, when we wrap the function parentheses, we’re essentially saying, treat this whole thing as an expression which is evaluated immediately and does not necessarily require naming or assignment.

When you execute the code on browser the code run but now the global namespace is not cluttered with my variable.

(+) and (!) signs in javascript

A trick here is to replace the closure with a plus sign (+) or an exclamation point (!) like this:

!function(){
function foo(){
console.log('helloworld');
};
foo();
}();

The reason for replacing with an exclamation point is if you are concatenating multiple files together.

Note** It is important that in the basic module pattern you have to remember to end every module with a semicolon.

Additionally, if you do not know which file comes first you need to add a semicolon in front like this:
;(function(){
function foo(){
console.log('helloworld');
};
foo();
}());

Note*** It is more elegant to use exclamation point (!) as shown above.

Also, with our module pattern is import other globes to be used within the module but with the reference, locally within the module.

Underscore Toolkit

A vary popular Javascript toolkit called underscore into our module. We’re going to bring it in as a parameter

!function(underscore){
function foo(){
console.log('helloworld');
};
foo();
}(_);

Benefits for using underscore

1. Renaming the variable makes it obvious that you are doing something different or special with this variable in your module. For instance, maybe you are going to extend underscore with some new methods.

!function(underscore){
underscore.somenewmethod = "New method started!";
}(_);

2. There’s also a slight performance benefit, this is because the variable is now referenced in the local scope. So when you call the variable the interpreter does not have to crawl through the global scope looking for the variable. See example below:

!function(underscore){
underscore.somenewmethod = "New method started!";
console.log(underscore.VERSION);
}(_);

Result 1.8.3
you can see the result of the method by _.somenewmethod
Result “New method started!”

3. Another benefit of importing variables is that Javascript is typically compressed and minified for use in production. Compressors cannot rename global variables, however, minifiers or compressors are able to rename global variables that have been invoked with a local reference, and this is what we did with underscore. By importing it and using it locally.
By the way you don’t have to rename the variable itself, we could simply import the variable under the same name and we still have a local reference see below:

!function(_){
underscore.somenewmethod = "New method started!";
console.log(underscore.VERSION);
}(_);

You can read more on Minification http://alistapart.com/article/javascript-minification-part-II

Module Export Pattern

Is the pattern which keep your code from cluttering the global namespace and you want to share information with different parts of your application.

var awesomeNewModule = (function(){
var exports = {};

exports.helloWorld = function() {
console.log(“Hello World!”);
};
return exports
}());

Assigning the entire module to a variable called aweosmeNewModule
Create a local object called exports which will serve as a container of sorts.
Now we gonna assign a method to exports called helloMars, and we are going to return the entire exports object.

In the browser you can see that we can access awesomeNewModule along with the helloMars method

var awesomeNewModule = (function(){
var exports = {
foo: 5,
bar: 10
};

exports.helloWorld = function() {
console.log(“Hello World!”);
};

exports.goodbyeWorld = function() {
console.log(“Goodbye World!”);
};

return exports

}());

Now on the browser you can access all of these values and methods via my module.

Loose Augmentation

One of the best things a JavaScript application can do for performance is to load scripts asynchronously. We can create flexible multi-part modules that can load themselves in any order with loose augmentation.

See example below:

var awesomeNewModule = (function(exports){
var exports = {
foo: 5,
bar: 10
};

exports.helloWorld = function() {
console.log(“Hello World!”);
};

exports.goodbyeWorld = function() {
console.log(“Goodbye World!”);
};

return exports

}(awesomeNewModule || {}));

In order to implement this pattern we need to add a simple piece of logic. If awesomeNew Module exists then import it otherwise is simply an object. Since we use the exports keyword, we can say that awesomeNewModule is exports within the function. All the values inside the function with either get assigned to an empty object if this was the first file or the will assigned an extend awesomeNewModule, if this file was loaded after the module had already been created.

The last file loaded will overwrite any methods or values were named the same in previous files. For this reason you can not share values across the modules. If any aspect of one module depends on another, then you can’t safely depend on those values.

The whole point of writing modular code is that you split your app into pieces that don’t depend on each other. This way if one module introduces a breaking error to the applciation does not affect the rest of the code. Additionally, there are ways to add safeguards to make sure that one module doesn’t overide patterns or methods created from another module.

One final pattern we’ll look at is almost exactly the same export module pattern andf is called the sub module patten. The value of the sub module pattern is that you can namespace your application even further.

See example below:

var awesomeNewModule.sub = (function(exports){
var exports = {
foo: 5,
bar: 10
};

exports.helloWorld = function() {
console.log(“Hello World!”);
};

exports.goodbyeWorld = function() {
console.log(“Goodbye World!”);
};

return exports

}(awesomeNewModule.sub || {}));

Sub-modules pattern

Sub-modules have all the advanced capabilities of normal modules, including augmentation and private state.

Resources

Minification: http://alistapart.com/article/javascript-minification-part-II

Using the !, +, -, ~ sign before function: http://stackoverflow.com/questions/3755606/what-does-the-exclamation-mark-do-before-the-function

Leave a Reply

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More