7

I have written code to achieve

sum(1)(2) //3

the code looks like:

function sum(a) {

  return function(b) { 
    return a+b
 }

}

But I didn't work out the second question, which is how to achieve any arbitrary number of chain function call like:

sum(1)(2) == 3
sum(5)(-1)(2) == 6
sum(6)(-1)(-2)(-3) == 0
sum(0)(1)(2)(3)(4)(5) == 15
Huibin Zhang
  • 1,072
  • 1
  • 15
  • 30

4 Answers4

12

Normally you'd do something like this:

var add = function(a,b){
    return a+b;
};

var sum = function(){
    return [].reduce.call(arguments, add);
}

And then you can write:

sum(1,2,3,4); // 10

But it is possible to hack the functionality you're after:

var sum = function(x){
    var f = function(y){
        return sum(x+y);
    };
    f.valueOf = function(){
        return x;
    };
    return f;
};

sum(1)(2)(3)(4); // 10

Just don't do it in production code please!

1983
  • 5,882
  • 2
  • 27
  • 39
  • This is very clever. Probably too clever for real-world use, as your answer suggests. Nevertheless, it's accurate and very thought-provoking. – Joel Anair Oct 30 '14 at 16:44
  • Very nice! You can also add `f.toString = function(){ return x+""; };` to allow for stuff like `alert(sum(1)(2)(3)(4))` if you wish. – FrancescoMM Mar 13 '19 at 18:13
1

You can't do this - how does the sum function know whether you want it to return the answer or another function?

You could do something along these lines though:

sum(0)(1)(2)(3).result()

Implemented like this:

var sum = (function(){
    var total = 0;
    var f = function(n){
        total += n;
        return f;
    };
    f.result = function(){
        return total;
    };
    return f;
}());
codebox
  • 19,927
  • 9
  • 63
  • 81
1

As user codebox already said: This is not possible.

What you can do instead is to take the current parameter of the function into account. If there is no parameter you can return the result:

sum(1)(2)() == 3

Here is the implementation:

var sum = (function() {
    var total = 0;
    return function add(a) {
        if(a === undefined) {
            return total;
        }
        total += a;
        return add;
    };
}());
friedi
  • 4,350
  • 1
  • 13
  • 19
0

There's a handful of different ways to pass an "arbitrary" amount of arguments to a function. Perhaps the most useful for your case is the arguments object. In the scope of every function is an array-like object that holds all of the arguments passed to the function.

function shout(msg) {
    for (var i = 0; i < arguments.length; i++)
        console.log(arguments[i]);
}

shout("This", "is", "JavaScript!"); // Logs all three strings, one line at a time

Despite it seeming like the function only accepts one argument, you can plug in as many as you'd like, and the function will cycle through all of them. Thus, converting this for your code:

function sum(a) {
    var total = 0;

    for (var i = 0; i < arguments.length; i++)
        total = total + arguments[i];

    return total;
}

sum(1, 2); // Returns 3

Two things to note:

  • Because you're accessing the arguments object, you really don't "need" any sort of arguments list in the function definition (i.e. you don't need the a in sum(a)), but it's generally considered a good idea to provide some indication of what the function expects.
  • The arguments object is array-like, but is NOT a true array; don't go trying to use array functions on it such as push or pop unless you want to make a mess of things.

As for the specific sum(1)(2) syntax however--if that is very specifically what you need--I'm stumped. In theory, to have an arbitrary chain like that, you'd need your function to return an object that is both a function and a number... which breaks fundamental rules of JavaScript. I don't think it's possible without some extremely clever (and likely extremely dangerous) editing of built in objects, which is generally frowned upon unless there is an extremely good reason for doing so.