JavaScript函数柯里化的简单实现

简单来讲,柯里函数就是只接受一个参数的函数,柯里化的起源请参看这篇文章:函数式编程入门教程
一般来说,若是三个数求和的函数咱们会这样写:javascript

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

若是只考虑实现这个函数的柯里化,咱们能够这样作:html

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

观察上面两种不一样的写法能够发现,第二种写法其实就是首先把三个参数收集起来,而后到最后再调用第一种写法的函数:java

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

因此柯里化的写法只是把经常使用写法包装了一下,可使用一个专用的柯里化函数实现这种包装。柯里化函数是一种高阶函数,咱们把它命名为curryes6

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)
}

测试一下,在线democode

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

相关文章
相关标签/搜索