函数柯里化
用过loadsh的都大概了解过其中提供了一个curry方法,可以把传参拆分开延迟执行;把简单函数复杂化,复杂化是为了通用性,为了能够更灵活调用,重复使用。
比如:
function num(a, b, c) {
console.log(a,b,c)
}
这个函数经过柯里化后
const curryNum = curry(num);
可以分开传参
curryNum(1)(2)(3);
curryNum(1)(2, 3);
curryNum(1, 3)(3);
// 或者
const curryNums = curryNum(1);
curryNums(2)(3);
等等操作
简单来说就是相当于抽离出复用的函数来便于后面再复用,举个栗子。
封装正则校验函数以便于复用
function checkByReg(reg, data) {
return reg.test(data)
}
const checkMobile = checkByReg(/^1\d{10}$/, '13302909105');
const checkMobile1 = checkByReg(/^1\d{10}$/, '12345678901');
const checkMail = checkByReg(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '123@outlook.com');
…等等
是不是发现这样写很不cooooooooool,感觉还可以再封装一遍抽离相同的正则再传参校验。
如果使用柯里化的话,是不是可以更灵活?
const curryCheck = curry(checkByReg);
const checkMobile = curryCheck(/^1\d{10}$/);
const checkMail = curryCheck(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);
checkMobile('13302909105');
checkMail('123@outlook.com');
那么 这个curry方法是怎么实现的呢?
下面来一个简易版的柯里化函数
/**
* fn 需要柯里化的函数
* len fn的形参个数
* args 传入的形参
*/
function _curry(fn, len, ...args) {
// 利用闭包特性接收传入参数
/**
* params 拆分传入的参数
*/
return function(...params) {
// 已收集到的参数
const _args = [...args, ...params];
// 当收集的参数已经跟函数的参数个数一致时返回该函数并将所有参数传进来
if (_args.length >= len) {
return fn.call(this, ..._args)
} else {
// 没有收集完则继续递归
return _curry(fn, len, ..._args)
}
}
}
/**
* 将函数柯里化
* @param fn 待柯里化的原函数
* @param len 所需的参数个数,默认为原函数的形参个数
*/
function curry(fn, len = fn.length) {
return _curry.call(this, fn, len)
}
此时柯里化函数完成了,回到开头,调用柯里化num函数
const curryNum = curry(num);
curryNum(1)(2)(3); // 1,2,3
curryNum(1)(2, 3); // 1,2,3
可以看出来 js里函数柯里化实则是利用闭包和递归去收集每次传入的参数,直到实参个数和形参个数一致时返回并传入全部参数;
… end