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.
return document,body.appendChild( document.createElement(div) );
}
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.
$( ''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 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 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 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:
return document.body.appendChild(document.createElement('div'));
});