7.1. JavaScript module patterns

Warning

You are looking at documentation for an older release. Not what you want? See the current release documentation.

Why module patterns?

As you might experience before, some problems that you often have to deal with in JavaScript are:

In eXo Platform, your application is not a whole page. Your portlet and gadget can be added to a page containing many other applications. That emphasizes the importance of modularity. You need to understand the module patterns to write JavaScript safely, even if you are writing only one script file that will use JQuery.

Closure and self-invoking

Let's see an example of global variables. In the page you have a button that counts the number of clicks on it:


<!DOCTYPE html>
<html>
<head>
<script>
    var counter = 0;
    function count(){
        counter++;
        document.getElementById("result").innerHTML = counter;
    }
</script>
</head>
<body>
    <p>You've clicked <span id="result">0</span> times!</p>
    <button onclick="count();">Click me</button>
</body>
</html>

Here you maintain a global variable that increases each time users click on the button. The code should work, but the problem is the variable can be modified by any other code of the page.

If you make the variable a function-scoped one that can only be changed by the function, it will not work as expected because the variable is reset (to zero) every time the function is invoked.

The problem can be solved if you have a way to define a variable at function scope but is initialized only one time. The closure pattern is a JavaScript feature that makes it possible:


<script>
    var counter = (function(){
        var privateCounter = 0;
        return function(){ return privateCounter++; };
    })();
    function count(){
        document.getElementById("result").innerHTML = counter();
    }
</script>

Focus on the function declaration first:

function(){...}

It is an anonymous function that cannot be invoked by later code, but you make it invoke itself immediately - and only this time - by adding parentheses after the declaration:

(function(){...})();

By that way, the private variable is created only one time, but is accessible by any child function under the scope. The next thing is to return that child function to a variable that becomes the only access holder.


<script>
    var counter = (function(){
        var privateCounter = 0;                                                 //this runs only one time in self-invocation
        return function(){ return privateCounter++; };  //this keeps the access to the private variable
    })();
</script>

The module pattern

From the self-invoking function you can return not only a function but an object that contains many properties and functions. It makes the ability to create a namespace, or in other words, a module. The idea is to return an object with only things that you want to expose to the world, and keep the other things private.

Let's see how the code is built step by step before it completes the module pattern:

// create a new scope
(function (){

})();

// give it a name
var module = (function (){

})();

// private method and property
var module = (function (){
	var privateProperty = "smth";
	var privateMethod = function () {};
})();

// public method and property
var module = (function (){
	return {
		publicPropertyyy: "smth";
		publicMeeethod: function() { //some code };
	}
})();

// the complete form
var module = (function (){
	// private properties and functions
	return {
		// public properties and functions
	}
})();

// access it from outside
module.publicPropertyyy;
module.publicMeeethod();

The module extension pattern

You can add properties and functions to an existing module, by passing it as a parameter to a new self-invoking function:

var module2 = (function(module){
	module.extension = function() {};
	return module;
}(module || {});

A Java-like example

To ones who are more familiar with Java, this variation of the pattern is easy to understand because it imitates a simple Java class:

var module = (function(){
	//private
	var name = "default";
	var getName = function(){
		return name;
	};
	var setName = function(newName){
		name = newName;
	};
	
	//public
	var obj = {
		getName: getName,
		setName: setName
	};
	return obj;
})();

References

At this point you touch a JavaScript core feature which is the base for many libraries that support modularity. Next, you are introduced to AMD and RequireJS. But you may break to read some other references:

Copyright ©. All rights reserved. eXo Platform SAS
blog comments powered byDisqus