Reputation: 19854
I am trying to get my head around the various techniques that can be used to avoid the use of global variables in JavaScript.
Consider the following code, that performs a redirect to a URL after a countdown timer:
var _redirectTimer;
function startRedirectTimer() {
clearTimeout(_redirectTimer);
var redirectTimer = function(timeLeft) {
if(timeLeft == 0) {
// redirect to application path
var redirectURL = window.location.protocol+"//"+window.location.host + "/" + location.pathname.split("/")[1];
window.location.replace(redirectURL);
return;
} else {
timeLeft--;
_redirectTimer = setTimeout(function () {redirectTimer(timeLeft)}, 1000);
}
}
redirectTimer(60);
}
My client code only ever calls startRedirectTimer()
. However, _redirectTimer
is a global variable that I'd rather not expose.
Ideally, I'd like this variable to be a "state" variable within startRedirectTimer()
, similar to how you'd have a private method in a singleton java class.
Can someone advise on how I can achieve this?
Thanks
Upvotes: 0
Views: 138
Reputation: 76395
Well, the quick way around variables is just wrapping an extra function around the section in question:
(function()
{//wrapper function
var _redirectTimer;
function startRedirectTimer()
{
clearTimeout(_redirectTimer);
var redirectTimer = function(timeLeft) {
if(timeLeft == 0)
{
// redirect to application path
var redirectURL = window.location.protocol+"//"+window.location.host + "/" + location.pathname.split("/")[1];
window.location.replace(redirectURL);
return;
}
else
{
timeLeft--;
_redirectTimer = setTimeout(function () {redirectTimer(timeLeft)}, 1000);
}
}
redirectTimer(60);
})();//call wrapper function
As always, you can choose when to call the timeout function by exposing it to the global object. However, if I understood correctly you're looking for a way to contain the _redirectTimer
or link that to the startRedirectTimer
function somehow (obviously without it loosing its state after each call). This is possible, in a number of ways:
function startRedirectTimer()
{
//as you would, only: add this line
var _redirectTimer = startRedirectTimer._redirectTimer;
}
startRedirectTimer._redirectTimer;//functions are objects, so assign properties and methods at will
These properties and methods live as long as the function, so their values aren't reset after each call. Downside: they're publicly accessible, and can be redefined by accident.
Closures are the best fit for cases like this:
var startRedirectTimer = (function()
{
var _redirectTimer,timeLeft = 60;//initial value here
var redirectURL = window.location.protocol+"//"+window.location.host + "/" + location.pathname.split("/")[1];//
return function ()
{
clearTimeout(_redirectTimer);
if (timeLeft === 0)
{
return window.location.replace(redirectURL);
}
timeLeft--;
_redirectTimer = setTimeout(startRedirectTimer,1000);//just call the main function again
}
})();//return value of this function will be the actual startRedirectTimer function
To set things in motion with the code above, just call startRedirectTimer()
once, and it should work. It's untested code, this, and I'm a bit feverish today, but it should. IMO, less code, and more efficient.
Upvotes: 1
Reputation: 324640
You can enclose it in a closure:
(function() {
var _redirectTimer, redirectTimer;
window.redirectTimer = redirectTimer = function() {
// ......
}
redirectTimer(60);
})();
If you don't need redirectTimer
outside this closure, you can remove the window.redirectTimer =
part.
Upvotes: 0