函数sum(1)(2)(3)(4)...(n)实现无限累加

一开始看到这个题目我最先想到了闭包,

可能会这么写:

function sum(a){
    return function(b){
        return function(c){
            return function(d){
                ......
            }
        }
    }
}

或许也会这么写:

let sum = a => b => c => d => ... => a+b+c+d+...+n

但是不论是以上哪种方式,都需要先固定参数个数,因此这两种写法都不可取

解决办法——递归调用

方法一:使用toString打印

思路:当我们直接对函数使用 alert() 或 console.log() 时,函数的 toString() 方法会被调用。注意,valueOf方法会把数据类型转换成原始类型,toString方法会把数据类型转换成string类型,如果是对象会返回,toString() 返回 “[object type]”,其中type是对象类型。正常情况下,优先调用toString()。有运算操作符的情况下,valueOf()的优先级高于toString(),当调用valueOf()方法无法运算后还是会再调用toString()方法

代码:

function sum(a){
    let temp = function(b){
        return sum(a+b)
    }
    // temp.toString这里写成temp.valueOf也可以
    temp.toString = function(){
        return a
    }
    return temp
}

let ans = sum(1)(2)(3)
console.log(ans)

执行过程:这sum函数可以无限次循环调用,并且把所有传进去的值相加,最后返回所有值得总和。

  ①执行sum(1),此时a=1,返回temp函数

  ②执行temp(2),这个函数内执行sum(a+b),即sum(a+b)=sum(1+2)=sum(3),此时a=3,并且返回temp函数

  ③执行temp(3),这个函数内执行sum(a+b),即sum(a+b)=sum(3+3)=sum(6),此时m=6,并且返回temp函数

  ④后面没有传入参数,等于返回的temp函数不被执行而是打印。代码中的temp.toString的重写只是为了函数不执行时能够返回最后运算的结果值,这里即为6

方法二:函数柯里化

思路:也是用到toString打印,但是这里用到了函数式编程的思想,这里的sum(1)(2)(3)(4)...(n)等价于sum(1)(2,3)(4)...(n),也等价于sum(1,2,3)(4)...(n)等多种排列组合

代码:

let sum = 0
function add (...args) {
    for(let i=0;i<args.length;i++){
        sum = sum + args[i] 
    }
    return sum
}

function currying (fn) {
    let val = null
    let temp = function(...newArgs) {
        val = fn.apply(this, newArgs)
        return temp
    }
    temp.toString = function(){
        sum = 0
        return val
    }
    return temp
}

let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)) //15  这里是函数值为15,本质是函数字符串值
console.log(addCurry(1)(2)(3, 4, 5)) //15
console.log(addCurry(1, 2)(3, 4, 5)) //15

补充:

  ①函数柯里化就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。简单来说,就是每次调用函数时,它只接受一部分参数,并返回一个函数,直到传递所有参数为止

  ②toString返回的是函数字符串值,后期可以通过Number函数将函数字符串值转换为数值

扩展:求sum(1)(2)(3)...(n)()

方法一:

代码:

function sum(a){
    return function(b){
        if(b!==undefined){ 
            return sum(a+b)
        }else{
            return a
        }
    }
}

let ans = sum(1)(2)(3)()
console.log(ans)

方法二——函数柯里化

代码:

function add (...args) {
    //求和
    return args.reduce((a, b) => a + b)
}

function currying (fn) {
    let args = []
    return function temp (...newArgs) {
        if (newArgs.length) {
            args = [
                ...args,
                ...newArgs
            ]
            return temp
        } else {
            let val = fn.apply(this, args)
            args = [] //保证再次调用时清空
            return val
        }
    }
}

let addCurry = currying(add)
// 注意调用方式的变化
console.log(addCurry(1)(2)(3)(4, 5)())  //15
console.log(addCurry(1)(2)(3, 4, 5)())  //15
console.log(addCurry(1)(2, 3, 4, 5)())  //15

参考:

https://juejin.im/post/5e6ed0bc6fb9a07c8334f75c

https://juejin.im/post/5e40b566e51d4526ea7ee623

 

posted @ 2020-04-26 10:25  蛋片鸡  阅读(4367)  评论(0编辑  收藏  举报