Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
JerryWang
Advisor
Advisor

Before we start, let's look into the code below. What will be displayed in alert popup?



When function f is called, x = 3, y = 2. The main question here is inside function f, what is the value of x, 2 ( the original value when an anonymous function is assigned to variable f via function expression ) or 3 ( the actual value in the runtime ) ?



The answer is 3, so finally we get 3 displayed in popup.



Now check this example:



and we will get 2 this time, since the free variable x is bound to value of the lexical environment at declaration time, 2.


Example1 - AJAX callback


before we use Closure


In order to get which button is being clicked, we have to make use of oEvent passed in:



<html>
<body onload = "load();">
<div>
<button id="button1" width = "100px">button1</button>
<button id="button2" width = "100px">button2</button>
</div>
</body>
<script>
function load() {
registerEvent("button1");
registerEvent("button2");
}
function registerEvent(buttonID) {
var oButton = document.getElementById(buttonID);
if( !oButton)
return;
oButton.onclick = function(oEvent) {
debugger;
alert("button clicked, id: " + oEvent.srcElement.id);
};
}
</script>
</html>

after we use Closure


function registerEvent(buttonID) {
var oButton = document.getElementById(buttonID);
if( !oButton)
return;
oButton.onclick = (function() {
return function(){
alert("button clicked, id: " + oButton.id);
}
})();
}

The parameter oEvent is no longer needed.




Example 2 - Resource Lazy load design


Suppose when we try to log on WebQQ, the desktop background color should become dark to highlight the logon dialog.




Solution version 1


Create a new div element used as a mask layer.



var createMask = function(){
return document,body.appendChild( document.createElement("div") );
};
$('button').click(function(){
var mask = createMask();
mask.show();
});



 


Drawback: It makes sense for the mask div element to be a singleton, or else every time we click log on button, there will be a new div generated.



Solution version 2


I use the following code to achieve singleton.



var mask = document.body.appendChild(document.createElement(''div" ) );
$( ''button').click(function(){
mask.show();
});



 


Drawback: If log on button is never clicked, the mask div element is then not necessary. In this solution, the mask div is always created although not necessary.



Solution version 3


I use a global variable to check whether the mask div has already been created or not.



var mask;
var createMask = function(){
if(mask)
return mask;
else {
mask = document,body.appendChild( document.createElement(div) );
return mask;
}
}

Drawback: here a global variable outside createMask function is used and it is changed inside createMask. This is not safe since there is possibility that other JS file could also change it.

Solution version 4




 
var createMask = function() {
var mask;
return function() {
return mask || ( mask = document.body.appendChild(document.createElement('div')));
}
}();




 

Now the mask variable is wrapped inside Closure and not visible to outside consumers. The creation of mask div is delayed until it is really necessary.

Final solution


We can also write a generic function to enable any other function to behave as singleton style:
var singleton = function(fn){
var result;
return function() {
return result || ( result = fn.apply(this,arguments));
}
}



 


The singleton function accepts a function as input, and return a new function which behaves like singleton.

Our final solution could be:
var createMask = singleton(function(){
return document.body.appendChild(document.createElement('div'));
});



Simple test it. When createMask is created for the first time, result is initial, so the code after || is called to fill the result.

When called the second time, the result is returned directly.