有趣的面试题(1)

99 阅读2分钟

不找工作!

最近看到一个挺有意思的题,如下:

// 编写一个 add 函数,要求如下均打印 6
console.log(add(1,2,3))  //  打印6
console.log(add(1)(2,3))  //  打印6
console.log(add(1)(3)(2)) //  打印6
console.log(add(1,2)(3))  //  打印6

回到学生时代,遇到问题,那首选需要分析题目,该题存在如下一些点:

  1. 链式调用
  2. 闭包

首选分析一下链式调用,add()()

需要函数的返回值是一个函数,那么会存在如下结构:

const add = () => {
  return () => {}    
}

但题目明显没这么简单,因为这里是多层调用 add()()(),所以需要循环返回,改造如下:

const add = () => {
  const fn = () => {
    console.log('fn')
    return fn;
  }
  return fn;    
}

当我们执行 add()()() 时会打印2次 fn 并得到一个 fn 函数, 这样看上去满足了链式调用的需求,但如何将值给返回呢?

由于需要返回累加值,所以我们需要用到闭包的知识,魔改一下:

function add(){
 const args = [...arguments];
 function fn(){
   args.push(...arguments);
   console.log(args); // [1,2,3]
   return fn;
 }
 return fn;
};
add(1,2)(3); // fn

细心的你也许会问,这里为什么不用 es6 的箭头函数了,原因是我们需要使用 arguments,箭头函数没有 arguments 吗? 不是没有,是没有自己的 arguments,这涉及到作用域了,有兴趣的可以咨询查阅,不展开。

可以看出,我们已经将所有的形参保存 args 里面了,并返回了 fn,如何从 fn 上获取 args 的累加值?

这其实是这道题的难点,高考可以放到第 21 题了。

先简单介绍下 valueOf,其会返回指定对象的原始值。

'1'.valueOf(); // '1'
(1).valueOf(); // 1
[1,2].valueOf(); // [1,2]
const obj = {name: '柯南'};
obj.valueOf() === obj; // true

valueOf 除了可以返回原始值之外,我们还可以对其进行修改

const obj = {name: '柯南'};
obj.valueOf = () => '小明';
obj.valueOf(); // '小明'

因此,我们只需要修改 fn 的 valueOf 即可得到 reduce 值

function add(){
 const args = [...arguments];
 function fn(){
   args.push(...arguments);
   return fn;
 }
 fn.valueOf = () => args.reduce((a,b) => a + b, 0);
 return fn;
};
console.log(add(1,2,3).valueOf()); // 6
console.log(add(1,2)(3).valueOf()); // 6

满足要求了吗?好像并没有,求大哥指点。