如何完美实现一个add(1)(4, 5, 6)(7, 8)(10)=41

我看函数式编程的时候看到这样一个题:

如何实现一个函数add使得:add(1)(4,5,6)(7,8)(10) 输出 41 ?

我看通常的解法是这样

function add(...args) {
  function inner(...otherArgs) {
    args = [...args, ...otherArgs];
    return inner;
  }
  inner.toString = () => {
    return args.reduce((acc, cur) => acc + cur, 0);
  };
  return inner;
}
let res = add(1)(4, 5, 6)(7, 8)(10);
alert(res)

但是事实上, 这是有问题的
alert实际上默认调用了toString方法, 而实际开发中更常用的console.log则不会调用toString, 使用console.log(res)打印出来的结果会有问题

请问有没有什么方法能够完美解决这个问题呢?

阅读 3.1k
4 个回答

控制台 API 不是在任何规范中定义的标准 API,而是取决于具体浏览器的实现。

换而言之,你用 console.log 的结果就已经是不可预知的了。对应到 C/C++ 里的话,这就属于一个未定义行为。任何依赖未定义行为的解法反倒是不对的。

本题是为了考察函数柯里化的基本知识,已经如何覆写 toString 而已,跟你用什么浏览器并无关系。甚至于说,如果你的运行环境压根也不在浏览器里、压根就没有 console.log 方法、也不影响你作答。

P.S. 事实上,早期版本的 Chrome 即便你用 console.log,也确实是能输出 toString() 结果的;某个版本之后才开始原样打印 function 内部定义了 ———— 本来这也不是标准 API,Chrome 想怎么改就怎么改,说不定它们哪天又改回输出 toString() 了。

能做转换的,我知道的也就 3 个

  • [Symbol.toPrimitive]
  • .toString
  • .valueOf

如果这三个都解决不了问题,可能就想不到啥办法了

如果 console.log 没有标准,可以制定标准

console.log = (old_console_log => x => old_console_log(x.toString()))(console.log)

题目中说的是输出41,而不是函数最后计算结果为41,所以可以在add函数里面写console.log进行输出,判断当返回函数一段时间内没被调用则进行输出

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题