柯里化函数的思想有点类似于以下场景:
刘关张 桃园三结义
一般函数:
function say(name,time,address){
console.log(`我${name}于${time},与各位哥哥${address}`)
}
say("刘备","今日","桃园三结义") //我刘备于今日,与各位哥哥桃园三结义
say("关羽","今日","桃园三结义") //我关羽于今日,与各位哥哥桃园三结义
say("张飞","今日","桃园三结义") //我张飞于今日,与各位哥哥桃园三结义
柯里化函数:
function say(time) {
return function (address) {
return function (name) {
console.log(`我${name}于${time},与各位哥哥${address}`)
};
};
}
let setInof = say("今日")("桃园三结义");
setInof("刘备"); //我刘备于今日,与各位哥哥桃园三结义
setInof("关羽"); //我关羽于今日,与各位哥哥桃园三结义
setInof("张飞"); //我张飞于今日,与各位哥哥桃园三结义
在方法的调用上
一般函数公共属性写了太多太多次,不利于管理维护。
柯里化函数公共属性通过预执行已经存储在了变量setInof中,只需要传入不同的部分即可达到结果。
可是我们就遇到了问题,难道说科里化函数我定义的深度必须固定吗?那我写一次又一次科里化岂不是很累?我还不如开开心心的写着我们可爱的一般函数呢,不香吗?
其实,我们只要把上述科里化函数与一般函数结合起来,就会有更不可思议的结果。接下来为各位大佬双手奉上小弟的封装科里化的思路:
function say(name,time,address){
console.log(`我${name}于${time},与各位哥哥${address}`)
}
function sayPack(fn) {
let len = fn.length;
return function temp() {
let args = [...arguments];
if (args.length >= len) {
return fn(...args);
} else {
return function() {
return temp(...args, ...arguments);
};
}
};
}
let fn = sayPack(say);
fn ("刘备")("今日")("桃园结义") //我刘备于今日,与各位哥哥桃园结义
fn ("关羽")("今日")("桃园结义") //我关羽于今日,与各位哥哥桃园结义
fn ("张飞")("今日")("桃园结义") //我张飞于今日,与各位哥哥桃园结义
fn ("张三","今日")("哈牛皮") //我张三于今日,与各位哥哥哈牛皮
fn ("王五")("明天","斗地主") //我王五于明天,与各位哥哥斗地主
fn ("赵六","后天","熬夜加班") //我赵六于后天,与各位哥哥熬夜加班
fn ("置酒天晴","2020年10月25日","一起欢度1024程序员节,2020-1024=996,昨天加班到9点的我也许是天选之子?")
//我置酒天晴于2020年10月25日,与各位哥哥一起欢度1024程序员节,2020-1024=996,昨天加班到9点的我也许是天选之子?
以上便是科里化函数主体,通过向封装体抛入需要科里化的其他函数达成目的。
其中需要注意的是,无论方法体的()多么花哨,传递参数个数一定要与传入科里化封装的函数传参个数一致。就像你跟朋友逛鬼屋,进鬼屋与出鬼屋起码人数一样才能开开心心的吧?这毫无根据的多出来一个或者丢了一个,应该也蛮恶心的。
就函数体sayPack就逐行分析:
function sayPack(fn) {//定义方法体 传递方法进来
let len = fn.length;//获取方法体传入参数个数
//以上就是let fn = sayPack(say)做的事儿了
//以下则是fn("xxx")("xxx","xxx")的实现
return function temp() {
//重点:因为我们如果想要封装一个可以在任何地方都能使用的科里化封装体
// 我们就不能限定方法体传入参数个数。
// 可以利用arguments获取所有传入参数,与外面的len协调控制,完成方法实现
let args = [...arguments];//获取方法接收到的传参个数
if (args.length >= len) {//如果传入参数个数大于或len 则输入传入参数后的fn方法,并执行
return fn(...args);
} else {//如果传入参数个数小于len 则将传入参数与argumengts一起递归进temp制止if为真 执行
return function() {//a
//注意:这里的...arguments是针对上一句备注a的方法体,不是temp的arguments
// 这样先前传入的参数就能跟后传入的参数一起被temp的arguments整合到一个数组里
// 继续进行分流判断
return temp(...args, ...arguments);
};
}
};
}
如果有更漂亮的写法欢迎来讨论,让我们一起有条不紊的持续进步。
喜欢的话不妨点个小小的赞与关注,您的赞与关注将是我源源不断的前进动力。