函數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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM