Question

I'm trying to make a function that holds state but is called with foo().
Is it possible?

Was it helpful?

Solution

I believe this is what you want:

var foo = (function () {
    var state = 0;

    return function () {
        return state++;
    };
})();

Or, following the Wikipedia example:

var makeAccumulator = function (n) {
    return function (x) {
        n += x;
        return n;
    };
};

var acc = makeAccumulator(2);

alert(acc(2)); // 4
alert(acc(3)); // 7

JavaScript is one of those languages that has, IMHO, excellent support for functions as first class citizens.

OTHER TIPS

Since Javascript functions are first-class objects, this is the way to do it:

var state = 0;
var myFunctor = function() { alert('I functored: ' + state++);};

The state variable will be available to the myFunctor function in its local closure. (Global in this example). The other answers to this question have the more sophisticated examples.

There's no equivalent to just "implementing operator ()" on some existing object, though.

You can treat functions as objects and give them "member variables". Here we're using an internal function in fact, but instead of just declaring it as a local variable (var loop = ...), we're putting its definition outside of the function, using object syntax (fact.loop = ...). This lets us essentially "export" the internal loop function of fact so that it can be reused by the function doubleFact.

var fact = function(n) {
  return fact.loop(n, 1);
};

fact.loop = function(n, acc) {
  if (n < 1) {
    return acc;
  } else {
    return fact.loop(n-1, acc * n);
  }
};

var doubleFact = function(x) {
  return fact.loop(x * 2, 1);
};

console.log(fact(5)); // 120
console.log(doubleFact(5)); // 3628800

The same idea could be used to maintain state.

var countCalled = function() {
  console.log("I've been called " + (++countCalled.callCount) + " times.");
};

countCalled.callCount = 0;

countCalled(); // I've been called 1 times.
countCalled(); // I've been called 2 times.
countCalled(); // I've been called 3 times.

If you want to be able to instantiate multiple ones, each with their own state, try this:

var CallCounter = function(name) {
  var f = function() {
    console.log(name + " has been called " + (++f.callCount) + " times.");
  };
  f.callCount = 0;
  return f;
};

var foo = CallCounter("foo");
var bar = CallCounter("bar");

foo();
foo();
bar();
foo();
bar();
bar();
bar();

console.log(foo.callCount);
console.log(bar.callCount);

Outputs:

foo has been called 1 times.
foo has been called 2 times.
bar has been called 1 times.
foo has been called 3 times.
bar has been called 2 times.
bar has been called 3 times.
bar has been called 4 times.
3
4

You can use closure returning function with attached function object properties. Parameters of such functor (closure) could be changed after initialization, which can be useful when building some computation that can be run/configured later. Take a look at example below. This answer is similar to limp_chimp .

function functor() {

  var run = function runX() {

    return runX.functorParam;

    // or: 

    // return run.functorParam;
  };

  run.functorParam = 'functor param'; // default value

  return run;
}

var f1 = functor();

// call f1
f1(); // 'functor param'


// lets change functor parameters:
f1.functorParam = 'Hello';


// call f1
f1(); // 'Hello'

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top