JavaScript函数挑战:add(1,2)和add(1)(2)应该都返回3。

6

我的一个朋友向我提出了挑战,要求我编写一个能够同时处理这两种情况的函数。

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

我的直觉是编写一个返回它自身的add()函数,但我不确定我是否朝着正确的方向前进。这尝试失败了。

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

alert(add(1)(2));

因此,我开始阅读有关返回其他函数或返回自身的函数的内容。

我将继续尝试,但如果有人有一个巧妙的解决方案,我很想看看!


1
@MarkC。像这样的问题需要一个客观的获胜标准才能成为PPCG上适合的话题。在当前状态下,这个问题不太适合,并且已经被搁置 - Dennis
我认为@Partric Roberts的回答更好,你能把他的回答标记为正确吗? - Weijing Lin
8个回答

11

我写了一个柯里化函数,无论每次传递多少参数,它的valueOf()方法和函数上下文 (this)都与sum绑定。

/* add function */
let add = function add(...args) {
  const sum = args.reduce((acc, val) => acc + val, this);
  const chain = add.bind(sum);
  chain.valueOf = () => 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 */
let add7 = add(7);
console.log('let add7 = add(7)');
console.log('add7(3) = ' + add7(3));
console.log('add7(8) = ' + add7(8));

两种机制都是必要的原因在于,add() 函数体必须使用被调用函数的绑定上下文才能访问中间部分应用的总和,而调用站点必须使用 valueOf() 成员(隐式或显式地)才能访问最终总和。

有没有办法在不使用console.log()的情况下使其工作? - Sarath S Nair
@SarathSNair 是的,可以使用 Number() 或一元运算符 + 进行类型转换。 - Patrick Roberts
怎么做呢?如果我调用add(1,2)(3)而不是console.log('add(1, 2)(3) = ' + add(1, 2)(3)),我想得到6。 - Sarath S Nair

6

有一篇关于JavaScript中“柯里化和部分函数”的Dr.Dobs杂志文章描述了这个问题。

该文章中提出的一个解决方案是:

// 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;
}

4
如果y被明确地传递为undefined,请尝试使用arguments.length < 2代替typeof y === "undefined"。请注意,不要改变原来的意思。 - Patrick Roberts

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

1
无论x的值是多少,add(0,x)始终返回0。而add(0)(x)则会导致TypeError错误。 - Adam Jenkins
@Adam:没错。在这种情况下最好检查 undefined 或者上面答案中提到的 arguments.length - simon574

0
你要找的概念叫做“柯里化”,它与函数转换和部分函数应用有关。当你发现自己一遍又一遍地使用相同的参数调用同一个函数时,这将非常有用。
通过柯里化实现add(2)(6)的示例如下...
function add(x,y) { 
  if (typeof y === 'undefined') {
    return function(y) {
      return x + y;
    }
  }
}

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

此外,您可以这样做...
var add6 = add(6);
typeof add6; // => 'function'
add6(4);     // => 10

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

一种依赖于环境的扩展解决方案:

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
我们可以使用JavaScript提供的闭包概念。
代码片段:
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
通常你需要达成一个协议,确定函数应该返回一个函数(以便传入更多参数)还是最终结果。想象一下add函数也必须像这样工作:
add(1, 2, 3)(4, 5)  // -> 15

...然后就变得模糊了,因为你可能还想再次调用:

add(1, 2, 3)(4, 5)(6)  // -> 21

...所以add(1, 2, 3)(4, 5)应该返回一个函数,而不是15。

比如说,你可以同意需要再次调用函数但不带参数,以便获得数值结果:

function add(...args) {
    if (args.length === 0) return 0;
    let sum = args.reduce((a, b) => a+b, 0);
    return (...args) => args.length ? add(sum, ...args) : sum; 
}

console.log(add()); // 0
console.log(add(1,2,3)()); // 6
console.log(add(1,2,3)(4,5)()); // 15
console.log(add(1,2,3)(4,5)(6)()); // 21


-1
有些人可能认为他/她必须调用同一个函数两次,但如果你深入思考,你会意识到问题非常简单,你只需调用一次add函数,然后需要调用add函数返回的任何内容。
function add(a){
    return function(b){
        return a+b;
    }
}
console.log(add(20)(20));
//output: 40

你可以返回任意多次函数。假设y = mx+c。

const y= function (m){
    return function(x){
        return function (c){
            return m*x+c
        }
    }
}

console.log(y(10)(5)(10)); 
//out put: 60

不需要深思熟虑,我注意到OP想让add(2,4)返回6。 - trincot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接