什么是函数柯里化
函数柯里化,是把函数的多个参数拆分,变成接收小于原来参数个数(一般是一个)的函数。然后该函数返回还是函数,可以继续接受参数,直到没有参数传入或者传入的参数和定义的参数已经相等了,才执行函数。
结合例子来看看:
正常的add函数:
function add (a, b) {
return a + b
}
add(1, 1) // 2
把函数改成柯里化:
function add (a) {
return function (b) {
return a + b
}
}
add(1)(1) // 2
这个只是个是很简单的版本,只是想通过这个例子让你们认识下柯里化。
认识了柯里化之后,下面看看怎样改进。
改进的函数柯里化
大家可以看到,上面的add函数只能传2个参数,传多了没效果,传少了也不行
我期待的add函数不需要固定参数,可以动态变化
第一种写法
function curry(fn) {
const len = fn.length
return function anonymous(...args) {
if(args.length >= len) {
return fn.apply(null, args)
} else {
return anonymous.bind(this, ...args)
}
}
}
function add (a,b,c) {
return a + b + c
}
add = curry(add)
add(1)(1)(1) // 3
add(1)(1,1) // 3
add()(1,1,1) // 3
解析:
- 这里是把add函数当作参数传入curry中,记录add函数的长度(接受几个参数),返回一个新函数
- 在新函数里面判断如果函数传入的参数大于等于add函数的长度,则直接执行函数
- 如果小于则继续返回该函数。直到函数传入的参数大于等于add函数的长度,此时执行函数,然后返回。
这个函数是根据add定义的参数作判断,如果你定义的参数是2个,则传入2个参数就会执行,如果你定义的参数是3个,则传入3个参数就会执行。
这个就是需要定义add函数的时候要确定参数的个数。
如果我定义add函数的时候,不想确定参数的个数呢?
答案是可以的。
第二种写法
function curry(fn) {
let args = []
return function anonymous() {
if(arguments.length === 0) {
const params = [...args]
args = []
return fn.apply(null, params)
} else {
args.push(...arguments)
return anonymous
}
}
}
function add (...args) {
return args.reduce((acc, prev) => acc + prev)
}
add = curry(add)
add(1)(1)(1)() // 3
add(1)(1,1)() // 3
解析:
这个写法可以支持add函数不定参数,原理是根据最后执行的时候如果是空参数,则执行该函数。 所以当你参数传完了之后再加上一个空参数的执行,就可以了。
再看看另一种写法:
第三种写法
function add(...args) {
let fn = function (...args1) {
args.push(...args1)
return fn
}
fn.toString = function () {
return args.reduce((acc, prev) => acc + prev)
}
return fn
}
add(1)(1) == 2 // true
add(1,1) == 2 // true
add(1)(1)(1) == 3 // true
add(1)(1,1) == 3 // true
add(1)(1,1).toString() // 3
+add(1)(1,1) // 3
add(1)(1,1) + '' // 3
解析: 这个是利用调用add函数时生成一个新函数,然后改写了这个新函数的toString方法并返回该新函数。
所以调用add函数都是返回函数,如果你console出来就是一个函数,因为改写了toString方法,所以可以利用隐私转换(如果不了解隐私转换,可以看看我之前这篇文章)或者调用toString方法去得到期望的值。
总结
以上就是函数柯里化的几种写法,它不局限于只有一种写法,可以灵活多变。大家可以都看看学习,找到适合自己的。希望对你们有帮助。