前言
什么是柯里化?
柯里化就是将一个接收多个参数的函数,转化为多个函数,每个函数都只接收一个参数并返回一个新的函数,直到所有参数都被提供完毕。
示例
手写一个 add 函数实现两数相加
javascript
function add(a, b) {
if(arguments.length < 2) {
console.log('参数不足');
return
}
// 数据类型, 参数数量的问题
if(typeof a != 'number' || typeof b != 'number') {
console.log('类型错误');
return
}
return a + b;
}
console.log(add(1, 2));
console.log(add(1, '2'));
console.log(add(1));
打印结果
还可利用闭包完成一个add,实现分布接收参数,一次只接收一个参数
javascript
function add(a) {
// 第一个参数a
return function(b) {
return a + b;
}
}
console.log(add(2)(4));
打印结果
分析
add函数执行完成后,会返回一个匿名函数function,function执行完要返回 a + b
的值,由于a是add函数的值,function要用到a的值,所以add在执行完毕后会生成一个闭包里面存放了a的值,function会在这个闭包里寻找a的值,最后做加法运算并返回值。
如果参数不定,该如何实现?
对于es5,函数内置了一个arguments
对象,它包含了传给该函数的所有参数,可以通过arguments[i]
来访问这些参数。
javascript
const curry = function (fn) {
// 参数对象
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
function add(x, y, z, m) {
return x + y + z + m;
}
curry(add, 1, 2, 3)
打印结果
对于es6,为了让代码更加简洁,引入了 ...args rest
运算符,其能够接收任意数量的参数,并将它们以数组的形式收集起来。
javascript
const curry = (fn, ...args) => {
console.log(args);
}
function add(x, y, z, m) {
return x + y + z + m;
}
curry(add, 1, 2, 3)
打印结果
注: 如果使用了箭头函数 arrow function ,又去使用了es5 里面的arguments,由于箭头函数里面没有arguments,违反了es6 简洁的原则,所以应该用rest 运算符
柯里化的思路:
定义一个curry函数,用于将add函数需要的参数逐个传入,并且需要一个判断语句 args.length >= fn.length ? fn(...args) :(..._args) => curry(fn, ...args, ..._args)
,如果传入的参数大于或者等于fn所需要的参数个数,则执行fn(...args)
,将...args
所接收到的所有参数传给fn;否则,执行(..._args) => curry(fn, ...args, ..._args)
,返回一个新的柯里化函数,..._args
继续接收参数,并且将已有的参数...args
与新参数进行合并,再递归调用curry函数,直到接收到的参数足够调用fn。
php
const curry = (fn, ...args) =>
args.length >= fn.length
? fn(...args)
:(..._args) => curry(fn, ...args, ..._args)
// 原函数
// 柯里化,慢慢收集参数
const add = (x, y, z, m) => {
return x + y + z + m
}
console.log(curry(add, 1)(2)(3)(4));
打印结果
总结
快去自己手搓一个柯里化函数,实现逐个传参。