DJ180
DJ180

Reputation: 19854

JavaScript: Avoiding global variables in my functions

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

Answers (2)

Elias Van Ootegem
Elias Van Ootegem

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

Niet the Dark Absol
Niet the Dark Absol

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

Related Questions