Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to have a function toggle between two different processes?

Tags:

javascript

I have a function that I want it execute alternating processes every time it's triggered. Any help on how I would achieve this would be great.

function onoff(){
    statusOn process /*or if on*/ statusOff process
}
like image 242
fancy Avatar asked Jun 02 '11 20:06

fancy


4 Answers

One interesting aspect of JavaScript is that functions are first-class objects, meaning they can have custom properties:

function onoff() {
    onoff.enabled = !onoff.enabled;
    if(onoff.enabled) {
        alert('on');
    } else {
        alert('off');
    }
}

For this to work, your function should have a name. If your function is anonymous (unnamed), you can try to use arguments.callee to access it, but that is deprecated in the new ES5 standard and not possible when using its strict mode.

like image 163
PleaseStand Avatar answered Nov 12 '22 14:11

PleaseStand


With the use of closures, you can define a static variable that is only accessible by the function itself:

var toggle = (function()
{
    var state = true;

    return function()
    {
        if(state)
            alert("A");
        else
            alert("B");

        state = !state;
    };
})();

Now you can repeatedly invoke toggle(), and it would alternate between "A" and "B". The state variable is unaccessible from the outside, so you don't pollute the global variable scope.

like image 45
Elian Ebbing Avatar answered Nov 12 '22 15:11

Elian Ebbing


Use closures. In addition to closures, this method demonstrates arbitrary arguments and arbitrary numbers of functions to cycle through:

Function cycler

function cycle() {
    var toCall = arguments;
    var which = 0;
    return function() {
        var R = toCall[which].apply(this, arguments);
        which = (which+1) % toCall.length;  // see NOTE
        return R;
    }
}

Demo:

function sum(a,b) {return a+b}
function prod(a,b) {return a*b}
function pow(a,b) {return Math.pow(a,b)}
function negate(x) {return -x;}

var f = cycle(sum, prod, pow, negate);
console.log(f(2,10)); // 12
console.log(f(2,10)); // 20
console.log(f(2,10)); // 1024
console.log(f(2));    // -2
// repeat!
console.log(f(2,10)); // 12
console.log(f(2,10)); // 20
console.log(f(2,10)); // 1024
console.log(f(2));    // -2

Arbitrary cycler

Alternatively if you do not wish to assume all cycled things are functions, you can use this pattern. In some ways it is more elegant; in some ways it is less elegant.

function cycle() {
    var list = arguments;
    var which = 0;
    return function() {
        var R = list[which];
        which = (which+1) % toCall.length;  // see NOTE
        return R;
    }
}

Demo:

var cycler = cycle(function(x){return x}, 4, function(a,b){return a+b});
cycler()(1);   // 1
cycler();      // 4
cycler()(1,5); // 6
// repeat!
cycler()(1);   // 1
cycler();      // 4
cycler()(1,5); // 6

NOTE: Because javascript thinks 10000000000000001%2 is 0 (i.e. that this number is even), this function must be three codelines longer than necessary, or else you will only be able to call this function 10 quadrillion times before it gives an incorrect answer. You are unlikely to reach this limit in a single browsing session... but who knows

like image 3
ninjagecko Avatar answered Nov 12 '22 14:11

ninjagecko


If I'm understanding what you want, this may be what you're looking for:

var AlternateFunctions = function() {
    var one = function() {
        // do stuff...

        current = two;
    }, two = function() {
        // do stuff...

        current = one;
    }, current = one;
    return function() {
        current();
    }
}();

Then calling AlternateFunctions(); will cycle between one() and two()

like image 2
Robert Avatar answered Nov 12 '22 13:11

Robert