【问题标题】:Sum of range in Javascript in function local variable函数局部变量中 Javascript 范围的总和
【发布时间】:2017-03-08 22:02:36
【问题描述】:

我有范围函数和输出函数它们工作正常,现在我想创建 sum 函数用作范围函数中的 callbac 函数,但是当某些函数执行局部变量时,让我们说总或总和初始化 0(零),怎么能解决这个问题?

    function range(start,end,callback,step) {
        // body...
        step=step || 1;
        for(i=start;i<=end;i=i+step){
            callback(i);
        }
    }
    function output(a) {
        // body...
        console.log(a);
    }
    function sum(m){
       var total=0;
       // some code
}
    range(1,5,output);
    range(1,5,sum);

【问题讨论】:

    标签: javascript function closures higher-order-functions first-class-functions


    【解决方案1】:
     function range(start,end,callback,step) {
            // body...
            var aggregate;
            step=step || 1;
            for(i=start;i<=end;i=i+step){
                aggregate = callback(i, aggregate);
            }
        }
        function output(a) {
            // body...
            console.log(a);
        }
        function sum(m, aggregate){
           return m + aggregate;
        }
        range(1,5,output);
        range(1,5,sum);
    

    这样你甚至可以做一些很酷的事情,比如

    function conc(m, aggregate) {
        return aggregate + m.toString();
    }
    
    range(1,5,conc,2); //prints 135
    

    【讨论】:

      【解决方案2】:

      Continuition 风格的代码,就像你用 range() 开始的一样,会变得非常奇怪和麻烦。

      请注意定义您的局部变量。喜欢i

      function range(start,end,callback,step) {
        step=step || 1;
        for(var i=start; i<=end; i=i+step)
          callback(i);
      }
          
      function output(...label) {
        return function(...args){
          console.log(...label, ...args);
        }
      }
      
      function sum(callback){
        var total = 0;
        return function(value){
          //will log ever intermediate total, because sum() has no way to tell when the sequence is over.
          callback(total += +value || 0);
        }
      }
      
      range(1,5,output('range:'));
      range(1,5,sum(output('sum:')));

      在这种情况下,我更喜欢使用生成器,尽管高阶函数已经过时了。

      function *range(start,end,step) {
        step = +step || (end < start? -1: 1);
        for(var value = start, count = (end - start) / step; count-- >= 0; value += step)
          yield value
      }
      
      function sum(iterator){
        var total = 0, v;
        for(v of iterator) total += +v || 0;
        return total;
      }
      
      console.log("range:", ...range(1,5))
      console.log("sum of range:", sum(range(1,5)))
      
      //just to show that this works with your regular array as well
      console.log("sum of array:", sum([1,2,3,4,5])); 
      
      //and some candy, as requested by Bergi ;)
      //I like to stay with the interfaces as close as possible to the native ones
      //in this case Array#reduce
      var fold = (iterator, callback, start = undefined) => {
        var initialized = start !== undefined,
          acc = start,
          index = 0,
          value;
      		
        for(value of iterator){
          acc = initialized?
            callback(acc, value, index):
            (initialized=true, value);
          ++index;
        }
        if(!initialized){
          throw new TypeError("fold of empty sequence with no initial value");
        }
        return acc;
      }
      //and the ability to compose utility-functions
      fold.map = (callback, start = undefined) => iterator => fold(iterator, callback, start);
      
      console.log(" ");
      
      var add = (a,b) => a + b; //a little helper
      console.log('using fold:', fold(range(1,5), add, 0));
      
      //a composed utility-function
      var sum2 = fold.map(add, 0);
      
      console.log('sum2:', sum2( range(1,5) ));

      【讨论】:

      • 仍然可以为迭代器编写一个高阶折叠并使用它来实现sum :-)
      • @Bergi,我不确定我明白了。你的意思是喜欢为迭代器实现折叠然后fold(iterator, (a,b)=&gt;a+b)
      • 是的,完全正确(但不要忘记0
      • @Bergi,完成。我已将起始值设为可选(如在 Array#reduce 中)并添加了适当的逻辑来处理它。
      【解决方案3】:

      很明显,range 函数不应该接受回调,而是在现代 JavaScript 中采用 be a generator function,但是您问的是如何编写这样的回调。

      您已经用closures 标记了您的问题,它们确实是这里的方法。通过在每次调用外部函数时初始化一个新的total,您无需担心如何重置全局计数器。

      function makeSum() {
          var total=0;
          return function(m) {
              total += m;
              return total; // so that we can access the result
          }
      }
      
      var sum = makeSum();
      range(1, 5, sum);
      output(sum(0));
      

      【讨论】:

      • 这段代码工作正常。但是告诉我这段代码是如何工作的?为什么你创建 makeSum() 没有参数?在最后一行代码中,零是做什么的?
      • makeSum 不带参数调用,因为它不带参数。零(作为m 传递)只是为了不进一步增加总和,该调用的唯一目的是让total 回来(可能有其他方法可以实现这一点,但使用sum 似乎成为最短的解决方案)。
      【解决方案4】:

      如果回调不是未定义的,那么简单地调用范围数组上的回调就足够了吗?像这样:

      > function range(n, callback) {
          const r = [...Array(n).keys()]
          if (callback) {
            return callback(r)
          }
          return r
        }
      
      > function sum(arr) {
          return arr.reduce((a, b) => a + b, 0)
        }
      
      > range(10)
      
      > [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      
      > range(10, sum)
      
      > 45
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-07-13
        • 2021-12-18
        • 1970-01-01
        • 1970-01-01
        • 2013-10-14
        • 2018-09-02
        • 2012-11-05
        相关资源
        最近更新 更多