简单来说,柯里函数就是只接受一个参数的函数,柯里化的起源请参看这篇文章:函数式编程入门教程
通常来讲,如果三个数求和的函数我们会这样写:
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。