一、什么是函数柯里化
以下面这个例子为例,利用闭包将函数的参数打散的方式就是柯里化(curry),同理,还有偏函数(partial)
add(1,2,3) == add(1)(2,3) == add(1,2)(3) == add(1)(2)(3)
二、实现柯里化
// es6 通用的柯里化写法 (只适合函数参数长度固定的情况)
function curry(fn, ...args) {
return fn.length <= args.length ? fn(...args) : curry.bind(void 0, fn, ...args)
}
函数参数固定时
const add = (a,b,c) => a + b + c
const curriedAdd = curry(add)
console.log(curriedAdd(1)(2)(3)) // 6
函数参数不固定时
function curry(fn, ...args) {
return fn.length <= args.length ? fn(...args) : curry.bind(void 0, fn, ...args)
const add = (...args) => args.reduce((a,b)=>a+b,0)
const curriedAdd = curry(add)
console.log(curriedAdd(1)(2)(3)) // 报错
三、例题
// 请实现一个 add 函数, 满足以下功能
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
直接套模板得到结果如下:
// es6
function curry(fn, ...args) {
return fn.length <= args.length ? fn(...args) : curry.bind(void 0, fn, ...args)
}
const add = (a,b,c) => a + b + c
// const add = (...args) => args.reduce((a,b) => a + b, 0)
const curriedAdd = curry(add)
// 通用的柯里化方法限制了函数的参数,如下,打印结果 为 [Function function]
console.log(curriedAdd(1))
// 结果正确
console.log(curriedAdd(1)(2)(3))
const curriedAdd1 = curry(add, 1,2)
// 结果正确
console.log(curriedAdd1(3))
// 抛出异常
console.log(curriedAdd1(3)(3))
当入参不足函数形参长度时,会递归会返回函数本身,所以本题的难度在于重写函数的 toString 方法。
实现 add(1)(2)(3)
函数柯里化概念: 柯里化(Currying)是把接受多个参数的函数转变为接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。
1)粗暴版
function add (a) {
return function (b) {
return function (c) {
return a + b + c;
}
}
}
console.log(add(1)(2)(3)); // 6
2)柯里化解决方案
- 参数长度固定
对于add(3)(4)(5),其执行过程如下:var add = function (m) {
var temp = function (n) {
return add(m + n);
}
temp.toString = function () {
return m;
}
return temp;
};
console.log(add(3)(4)(5)); // 12
console.log(add(3)(6)(9)(25)); // 43
- 先执行add(3),此时m=3,并且返回temp函数;
- 执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数
- 执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数
- 由于后面没有传入参数,等于返回的temp函数不被执行而是打印,了解JS的朋友都知道对象的toString是修改对象转换字符串的方法,因此代码中temp函数的toString函数return m值,而m值是最后一步执行函数时的值m=12,所以返回值是12。
- 参数长度不固定
第 84 题:请实现一个 add 函数,满足以下功能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
14. 函数柯里化的实现