是否可以在JavaScript中创建一个仿函数?

时间:2022-09-18 22:00:45

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

我正在尝试创建一个保持状态但用foo()调用的函数。可能吗?

4 个解决方案

#1


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.

JavaScript是其中一种语言,恕我直言,作为一等公民的功能的极好支持。

#2


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

由于Javascript函数是第一类对象,因此这是实现它的方法:

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.

状态变量将在其本地闭包中用于myFunctor函数。 (本例中为Global)。这个问题的其他答案有更复杂的例子。

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

但是,对于某些现有对象,没有相当于“实现operator()”的功能。

#3


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 loop = ...),而是使用对象语法(fact.loop =。)将其定义放在函数之外。 ..)。这使我们基本上“导出”事实的内部循环函数,以便它可以被函数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

#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 .

您可以使用带有附加函数对象属性的闭包返回函数。初始化后可以更改这种仿函数(闭包)的参数,这在构建可以在以后运行/配置的某些计算时非常有用。看看下面的例子。这个答案类似于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'

#1


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.

JavaScript是其中一种语言,恕我直言,作为一等公民的功能的极好支持。

#2


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

由于Javascript函数是第一类对象,因此这是实现它的方法:

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.

状态变量将在其本地闭包中用于myFunctor函数。 (本例中为Global)。这个问题的其他答案有更复杂的例子。

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

但是,对于某些现有对象,没有相当于“实现operator()”的功能。

#3


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 loop = ...),而是使用对象语法(fact.loop =。)将其定义放在函数之外。 ..)。这使我们基本上“导出”事实的内部循环函数,以便它可以被函数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

#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 .

您可以使用带有附加函数对象属性的闭包返回函数。初始化后可以更改这种仿函数(闭包)的参数,这在构建可以在以后运行/配置的某些计算时非常有用。看看下面的例子。这个答案类似于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'