Closure is a procedure or a function, which body contains links to the variables, declared out of the function body but not as parameters of this function (but in the surrounding code).
Closures can be the reason of the memory leak.
The article contains most frequent cases of the closures use and the ways of their elimination:
Code with closure:
var oval = document.getElementById("div");
if (oval.addEventListener)
oval.addEventListener("onclick", function (event)
{
//You can work with oval from here
}, false);
else
oval.attachEvent("onclick", function (event)
{
//You can work with oval from here
});
Often, the closure is used to get access to the dom node the event is attached to.
The way to avoid closure:
function onclick(event)
{
this === oval
}
function test()
{
var oval = document.getElementById("div");
if (oval.addEventListener)
oval.addEventListener("onclick", onclick, false);
else
oval.onclick = onclick;
}
The specific is that the attachEvent function is no longer used, and the onclick property/event is used instead. It is required for this context in the event handler to be equal to the dom element with the attached event.
Code with closure:
var oval = document.getElementById("div");
setTimeout(function()
{
oval.innerHTML = "ok";
}, 100);
The way to avoid closure:
function test(oval)
{
oval.innerHTML = "ok";
}
setTimeout(test, 100, oval);
However, this code is not functional in the IE, because the test function in IE is always called without parameters. That is why the following function is used instead of the built-in one:
PP = {};
PP.IsIE = navigator.userAgent.indexOf(' MSIE ') > -1;
PP._onSetTimeout = function(index)
{
var callback = PP._onSetTimeout.tims[index];
delete PP._onSetTimeout.tims[index];
return callback.Handler.call(this, callback.Params);
};
PP._onSetTimeout.tims = [];
PP.setTimeout = function (func, delay, params)
{
if (PP.IsIE && typeof(params) != 'undefined')
{
var i = PP._onSetTimeout.tims.push({ Handler : func, Params : params}) - 1;
return setTimeout("PP._onSetTimeout(" + i+ ")", delay);
}
else return setTimeout(func, delay, params);
};
Code with closure:
var XHR = window.XMLHttpRequest ? new window.XMLHttpRequest() : new window.ActiveXObject("Microsoft.XMLHTTP");
XHR.onreadystatechange = function()
{
if (XHR.status == 200)
alert(XHR.responseText); //Here it is comfortable to use link to the XHR and call the required callbacks
};
The way to avoid closure:
function onreadystatechange()
{
if (this.status == 200) //this – is always XMLHttpRequest
alert(this.responseText);
};
var XHR = window.XMLHttpRequest ? new window.XMLHttpRequest() : new window.ActiveXObject("Microsoft.XMLHTTP");
XHR.onreadystatechange = onreadystatechange;
See also: