Javascript function challenge add (1,2) and add (1) (2) both should return 3

A friend of mine asked me to write a function that works with both of these scripts

add(2,4)  // 6
add(2)(4) // 6

      

My instinct was to write an add () function that returns itself, but I'm not sure if I'm heading in the right direction. It failed.

function add(num1, num2){
    if (num1 && num2){
        return num1 + num2;
    } else {
        return this;
    }
}

alert(add(1)(2));

      

So I started reading about functions that return other functions or return themselves.

I'll keep trying, but if anyone has a great solution, I'd love to see it!

+4


source to share


7 replies


Dr. Dobs has an article on Currying and Partial Functions in JavaScript "that describes exactly this problem.

One of the solutions found in this article:



// a curried add
// accepts partial list of arguments
function add(x, y) {
     if (typeof y === "undefined") { // partial
        return function (y) {
              return x + y;
        };
     }
   // full application
   return x + y;
}

      

+6


source


I wrote a function that generates the chain, function valueOf

and context this

) are constantly updated with a new sum, no matter how many arguments are passed each time.

/* add function */
function add() {
    "use strict";

    var args, sum, chain;

    args = Array.prototype.slice.call(arguments);
    sum = typeof this === 'number' ? this : 0;
    sum += args.reduce(function (p, n) { return p + n; }, 0);

    chain = add.bind(sum);

    chain.valueOf = function () {
        return sum;
    };

    return chain;
}

/* tests */
console.log('add(1, 2) = ' + add(1, 2));
console.log('add(1)(2) = ' + add(1)(2));
/* even cooler stuff */
console.log('add(1, 2)(3) = ' + add(1, 2)(3));
console.log('add(1, 2, 3)(4, 5)(6) = ' + add(1, 2, 3)(4, 5)(6));
/* retains expected state */
var add7 = add(7);
console.log('var add7 = add(7)');
console.log('add7(3) = ' + add7(3));
console.log('add7(8) = ' + add7(8));
      

Run codeHide result


The reason both mechanisms are required is because the next call in the chain cannot access the binding function valueOf

, and any script trying to evaluate the function as a number cannot access its context.



The only drawback is the requirement strict mode

to this

remain primitive.

Edited here to support both strict mode

non-strict mode:

function add() {
    var args, sum, chain;

    args = Array.prototype.slice.call(arguments);

    // Number object from non-strict mode
    if (this instanceof Number) {
        sum = Number(this);
    // number primitive from strict mode
    } else if (typeof this === 'number') {
        sum = this;
    // initial call to add
    } else {
        sum = 0;
    }

    sum += args.reduce(function (p, n) { return p + n; }, 0);

    chain = add.bind(sum);

    chain.valueOf = function () {
        return sum;
    };

    return chain;
}

      

+8


source


function add(num1, num2){
    if (num1 && num2) {
        return num1 + num2;
    } else if (num1) {
        return function(num2){return num1 + num2;};
    }
    return 0;
}

      

0


source


The concept you are looking for is called currying and it has to do with function conversion and partial function application. This is useful when you call the same function over and over again with the same arguments.

An example implementation add(2)(6)

via currying will look something like this:

function add(x,y) { 
  if (typeof y === 'undefined') {
    return function(y) {
      return x + y;
    }
  }
}

add(2)(4); // => 6

      

Alternatively, you can do something like this ...

var add6 = add(6);
typeof add6; // => 'function'
add6(4);     // => 10

      

0


source


var add = function(){
  // the function was called with 2 arguments
  if(arguments.length > 1)
    arguments.callee.first_argument = arguments[0];

  // if the first argument was initialized
  if(arguments.callee.first_argument){
    var result = arguments.callee.first_argument + arguments[arguments.length - 1];
    arguments.callee.first_argument = 0;

    return result;
  }else{// if the function was called with one argument only then we need to memorize it and return the same function handler 
    arguments.callee.first_argument = arguments.callee.first_argument || arguments[0];
    return arguments.callee;
  }
}
console.log(add(2)(4));
console.log(add(2, 4));

      

Advanced solution depending on environment:

function add(){
  add.toString = function(){
    var answer = 0;
    for(i = 0; i < add.params.length; i++)
      answer += add.params[i];
    return answer;
  };

  add.params = add.params || [];
  for(var i = 0; i < arguments.length; i++)
    add.params.push(arguments[i])

  return add;
}

console.log(add(2)(4)(6)(8))
console.log(add(2, 4, 6, 8));

      

0


source


I decided to add another solution for fun using some ES6 features:

/* add function */
const add = (function add () {
  const sum = [this, ...arguments].reduce((a, b) => a + b)
  const chain = add.bind(sum)

  chain[Symbol.toPrimitive] = hint => sum

  return chain
}).bind(0)

/* tests */
console.log('add(1, 2) = ${add(1, 2)}')
console.log('add(1)(2) = ${add(1)(2)}')
/* even cooler stuff */
console.log('add(1, 2)(3) = ${add(1, 2)(3)}')
console.log('add(1, 2, 3)(4, 5)(6) = ${add(1, 2, 3)(4, 5)(6)}')
/* retains expected state */
var add7 = add(7)
console.log('var add7 = add(7)')
console.log('add7(3) = ${add7(3)}')
console.log('add7(8) = ${add7(8)}')
      

Run codeHide result


0


source


We can use the concept of closures provided by Javascript.

Snippet of code:

function add(a,b){

    if(b !== undefined){

        console.log(a + b);
        return;

    }

    return function(b){
        console.log(a + b);
    }

}

add(2,3);
add(2)(3);

      

0


source







All Articles