qwertymk
qwertymk

Reputation: 35284

How can I keep track of multiple runs of the same function?

I have a function like this:

function run(arg) {
    if (!window.alreadyRun) init();
    window.alreadyRun = true;
    /* more code */
}

You get the idea, I'm trying to figure out if it's the first time a function is called.

Is there a better way to do this? Without using globals? Something like this:

function run(arg) {
    var ranAlready;
    if (!ranAlready) init();
    ranAlready = true;
    /* more code */
}

Upvotes: 2

Views: 182

Answers (4)

David Tang
David Tang

Reputation: 93684

I think closures are completely overkill for this, and only complicates the code.

What you're describing is known as a static variable in Object Oriented languages, and it can be mimicked quite easily in JS by attaching properties directly to the function. This is possible because functions are first-class objects in JS:

function run(arg) {
    if (!run.ranAlready) { // run.ranAlready is undefined at first, so falsy
       run.ranAlready = true;
       init();
    }

    /* more code */
}

This is far simpler than nested functions, and you can continue to use run() in exactly the same way.

Another advantage is that, for unit testing, you can still access the ranAlready property from outside the function to check that your code is working correctly:

assert(run.runAlready == false);
run();
assert(run.runAlready === true);

Granted, this can't be used for anonymous functions, such as in event handlers, but isn't it much cleaner to give that anonymous function a name instead of using nested functions and an extra function invocation?

Upvotes: 1

Jonathon Bolster
Jonathon Bolster

Reputation: 15961

Here's just another way to do it. You can have the function modify itself. In the case below, myfunction gets changed to a new one. This may not be exactly what you're looking for but I think it's useful to at least post this so you can see alternative ways to do things (and also: self modifying code can just be cool at times).

var myfunction = function() {
    alert("This is the first time I'm executed");

    myfunction = function() {
        alert('Subsequent times');
    }
}

myfunction();  // displays the alert 'This is the first time...'
myfunction();  // displays the alert 'Subsequent times'
myfunction();

Example: http://jsfiddle.net/jonathon/wntmB/

Upvotes: 0

alex
alex

Reputation: 490413

This will return a function, with a variable called runCount which will hold the number of times it was called.

var yourFunction = function() {
    var runCount = 0;

    return function() {
        console.log(runCount);
        runCount++;
    }  

}

var a = yourFunction();

a(); // runCount: 0
a(); // runCount: 1
a(); // runCount: 2
a(); // runCount: 3

See it on jsFiddle.

If you just want to run an init type function, you could place the code above returning the inner function. It will be called once before returning the inner function, and its scope will retain to its outer function.

Upvotes: 5

Raynos
Raynos

Reputation: 169451

The power of closures.

var f = (function(run) {
    return function() {
        if (!run) init(),run=true;
        // do code
    };
}(false));

You can even use if (!run) init() && run = true and get init to return false if you want it to be called again on the next function call.

We have a self executing function which creates a local run variable and set's it to false by passing it in as an argument. We then have a single line which checks if it's false if so it does init(), run=true which is running the init function and assigning it to true in a single expression.

Basically anywhere were your using global scope to make the variable static to the function you can instead use a closure as a scope level between local function scope & global scope.

If you need a variable that is static to a function & read only you can use the little known const keyword.

Upvotes: 2

Related Questions