支持add(1)(2)(3),add(1,2,3)两种累加调用

1,780 阅读1分钟

面试遇到一个题目,实现add函数,要支持add(1,2,3)以及add(1)(2)(3)两种调用方式。

思路

  1. 两种调用方式的区别可以根据argument长度来判断
  2. add(1,2,3)的实现可以通过argument参数的累加来实现
  3. add(1)(2)(3)的实现就难了,面试的时候没想出来,需要理解函数toString方法和闭包。

函数的toString()

toString()继承自Function.prototype.toString(),直接调用会返回当前函数源代码。在Function需要转换为字符串时,会自动调用函数的 toString 方法,像直接console.log函数。

Function.prototype.toString()覆盖了Object.prototype.toString(),后者直接调用会返回 "[object type]",其中 type 是对象的类型。

可以显示设置函数的toString,从而覆盖默认toString的行为。例如:

function any(a) {
    return a + 1
}
any.toString = function() { return 2 };
console.log(any)
//  ƒ 2

add(1)(2)(3)实现

版本1:

function add(a){
    let ret = function(){
        return add
    }
    ret.toString = function() { return a }
    return ret
}

这个版本改写了toString,调用add(1)会打印值1,并且返回add函数。但是它不能累加。

版本2:

function add(a){
    let ret = function(b){
        a = a + b
        return ret
    }
    ret.toString = function() { return a }
    return ret
}

add返回ret函数,ret函数内部依然返回ret,这样就实现了add函数的无限调用; 在ret中每次调用都改变a,利用闭包将累加结果保存到a变量。

最终add函数

function add(a){
    if(arguments.length > 1){
        return [...arguments].reduce((pre,val)=> pre+val, 0)
    }else{
        let ret = function(b){
            a = a + b
            return ret
        }
        ret.toString = function() { return a }
        return ret
    }
}
console.log(add(1,2,3));
console.log(add(1)(2)(3))
// 6
// f 6

得到正确结果,同时实现了add(1)(2)(3),add(1,2,3)的支持。

参考

  1. www.cnblogs.com/oxspirt/p/5…
  2. developer.mozilla.org/zh-CN/docs/…