JavaScript函數柯里化的簡樸完成

簡樸來說,柯里函數就是只接收一個參數的函數,柯里化的劈頭請參看這篇文章:函數式編程入門教程
一般來說,假如三個數乞降的函數我們會如許寫:

function _sum3(x, y, z) {
    return x + y + z
}

假如只斟酌完成這個函數的柯里化,我們能夠如許做:

function sum3(x) {
    return function(y) {
        return function(z) {
            return x + y + z
        }
    }
}
console.log(sum3(1)(2)(3)) // 6

視察上面兩種差別的寫法能夠發明,第二種寫法實在就是首先把三個參數網絡起來,然後到末了再挪用第一種寫法的函數:

function sum3(x) {
    return function(y) {
        return function(z) {
            return _sum3(x, y, z)
        }
    }
}
console.log(sum3(1)(2)(3)) // 6

所以柯里化的寫法只是把經常運用寫法包裝了一下,能夠運用一個專用的柯里化函數完成這類包裝。柯里化函數是一種高階函數,我們把它命名為curry

function curry(fn) {
    return function(y) {
        return function(z) {
            return fn(x, y, z)
        }
    }
}
var sum3 = curry((x, y, z) => {
    return x + y + z
})
console.log(sum3(1)(2)(3)) // 6

假如有要寫一種越發通用的,能夠柯里化具有恣意多個參數的函數呢,比方sumN(1)(2)(3)…(N),根據之前的寫法,大概是這個模樣的:

function curryN(fn) {
    return function(a1) {
        return function(a2) {
            return function(a3) {
                //......
                return function(aN) {
                    return fn(a1, a2, a3, ...aN)
                }
            }
        }
    }
}

很輕易想到能夠用一個遞歸函數來簡化這類寫法,將上面那些看起來類似的函數構造命名為nest,就能夠寫為:

function nest(fn) {
    return function(x) {
        return nest(fn)
    }
}
function curry(fn) {
    nest(fn)
}

這裏缺乏一個輪迴停止的推斷,所以nest函數先引入一個新參數i,當i === N時遞歸停止

function nest(fn, i) {
    return function(x) {
        if (i === N) {
            return fn(...)
        }
        return nest(fn, i + 1)
    }
}
function curry(fn) {
    return nest(fn, 1)
}   

接着,須要一個寄存恣意多個參數的數組,將這個數組命名為args,然後傳入nest函數

function nest(fn, i, args) {
    return function(x) {
        args.push(x)
        if (i === fn.length) {
            return fn(...args)
        }
        return nest(fn, i + 1, args)
    }
}
function curry(fn) {
    const args = []
    return nest(fn, 1, args)
}

末了在增加一個處置懲罰0個參數的狀況,我們就完成了最終版的柯里化函數

function curry(fn) {
    if (fn.length === 0) {
        return fn
    }
    const args = []
    return nest(fn, 1, args)
}

測試一下,在線demo

const log1 = curry((x) => console.log(x))
log1(10) // 10
const mul3 = curry((x, y, z) => console.log(x*y*z))
mul3(2)(3)(4) // 24

參考文章

Currying in JS
Currying in JavaScript ES6

    原文作者:Jeffrey
    原文地址: https://segmentfault.com/a/1190000014419080
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞