代码之家  ›  专栏  ›  技术社区  ›  the_drow

可以用JavaScript生成函子吗?

  •  14
  • the_drow  · 技术社区  · 15 年前

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

    4 回复  |  直到 8 年前
        1
  •  28
  •   Prestaul    15 年前

    我相信这就是你想要的:

    var foo = (function () {
        var state = 0;
    
        return function () {
            return state++;
        };
    })();
    

    或者 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是其中一种语言,它作为一等公民对函数有着极好的支持。

        2
  •  4
  •   Andreas Köberle    12 年前

    由于Javascript函数是一流的对象,因此以下是实现此目的的方法:

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

    这个 state myFunctor 函数的局部闭包。(本例中为全局)。这个问题的其他答案有更复杂的例子。

        3
  •  2
  •   limp_chimp    11 年前

    您可以将函数视为对象,并为它们指定“成员变量”。这里我们使用的是一个内部函数 fact ,而不是仅仅将其声明为局部变量( var loop = ... ),我们使用对象语法将其定义置于函数之外( fact.loop = ... ).这让我们基本上可以“导出”内部数据 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
    

    同样的想法也可以用来维持状态。

    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.
    

    如果希望能够实例化多个,每个都有自己的状态,请尝试以下操作:

    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);
    

    产出:

    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
  •  -1
  •   MKX    9 年前

    可以将闭包返回函数与附加的函数对象属性一起使用。 初始化后可以更改此类函子(闭包)的参数, 这在构建稍后可以运行/配置的计算时非常有用。看看下面的例子。这个答案类似于跛足黑猩猩。

    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'