2

I have range function and output functions they works correct,now I want create sum function for using as callbac function in range function,but when some function executed local variable let us say total or sum initialize 0(zero),how can solve this problem?

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

4 Answers4

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

This way you could even do cool stuff like

function conc(m, aggregate) {
    return aggregate + m.toString();
}

range(1,5,conc,2); //prints 135
Jean-Bernard Pellerin
  • 12,556
  • 10
  • 57
  • 79
1

Continuition style code, like you've started it with range(), can get really weird and cumbersome.

And please, please, mind defining your local variables. like 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:')));

In this case, I'd prefer using a generator instead, although the higher order functions get obsolete.

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) ));
Thomas
  • 11,958
  • 1
  • 14
  • 23
0

Clearly a range function should not take a callback but be a generator function in modern JavaScript, however you were asking how to write such a callback.

You've already tagged your questions with closures, and they are indeed the way to go here. By initialising a new total within each call of the outer function, you don't need to worry about how to reset a global counter.

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));
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • this code works correct.But tell me how this code works? why u create makeSum() without arguments? in last line code what does zero do? –  Mar 09 '17 at 04:20
  • `makeSum` is called without arguments because it takes no parameters. The zero (being passed as `m`) is just there to not further increase the sum, the only aim of that call is to get the `total` back (there might be other ways to achieve that, but using `sum` seemed to be the shortest solution). – Bergi Mar 09 '17 at 04:56
0

Won't simply calling the callback on the range array suffice if the callback is not undefined? Like this:

> 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