在以前的文章中对函数式编程作了一个简单的概述,在这篇文章中对一个你们喜闻乐见的话题——函数的柯里化进行一个总结。编程
⚠️注意: 柯里化和偏应用的概念常常被混用,在文中会有概念上的简单区分数组
这些概念仍是很好理解的,咱们的平常开发中老是伴随着这些函数:app
let log = (msg) => {console.log(msg)}
复制代码
let add = (x,y) => {return x+y}
复制代码
argements
获取全部参数,如今咱们每每会使用 ...args
由于这样咱们能够直接使用数组方法进行操做,形如function logAll(){
// arguments 不是数组,只是一个类数组对象
console.log(arguments);
}
logAll(1,2,3); // [1,2,3]
function logAllByES6(...arg){
// arg是数组,能够执行数组方法
console.log(arg.map((item)=>{return item*2}));
}
logAllByES6(1,2,3) // [2,4,6]
复制代码
根据一个相对通用的定义,函数的柯里化指:函数式编程
把一个多参数函数转换为一个嵌套的一元函数的过程函数
有一个很是典型的例子是add函数优化
// 柯里化前
function add(x,y){
return x+y;
}
add(1,2); // 3
// 柯里化后
function addCurried(x){
return function(y){
return x+y;
}
}
addCurried(1)(2); //3
复制代码
这样作的好处在于咱们能够经过这样的方式获得一系列新函数,从而让咱们优化数据的处理过程ui
偏应用又称做部分应用,偏应用的概念和柯里化有所区别,可是又很相似spa
事实上有不少文章中的柯里化指的就是偏应用,好比:code
function add(x,y,z){
return x+y+z;
}
add(1,2,3); // 6
// 柯里化
addcurried(1)(2)(3); // 6
// 偏应用
addPartial(1,2)(3); // 6
addPartial(1)(2,3); // 6
复制代码
实现的方式多种多样,写这篇文章的时候也参考了不少前辈的文章,有各类版本的实现,在ES6
的加持下还出现了“一行代码实现柯里化”这样的骚操做对象
不过在这里,我选择了比较容易被你们接受的实现方法记录在文中
如下实现方法参考了 Anto Aravinth
的实现,并作了一点小小的改动
let curry = (fn) => {
return function curriedFn(...args){
if(args.length < fn.length){
return function(...args2){
return curriedFn.apply(null,args.concat(args2));
}
}
return fn.apply(null,args);
}
}
let tipFunc = () => {console.log("经过柯里化,令 tipFunc 在指定事件后执行")}
let tipsTimer = curry(setTimeout)(tipFunc);
tipsTimer(10000); // 10s 后执行
tipsTimer(20000); // 20s 后执行
复制代码
// 偏应用函数
let partial = (fn,...partialArgs)=>{
let args = partialArgs;
return function(...fullArgs){
let arg = 0;
for(let i = 0;i < args.length && arg < fullArgs.length;i++){
if (args[i] === undefined){
args[i] = fullArgs[arg++];
}
}
return fn.apply(null,args);
}
}
let timer10s = partial(setTimeout,undefined,10000);
partial(()=>{console.log("经过偏应用,为setTimeout函数预先提供参数")});
复制代码