函数柯里化(Currying)
- 在计算机科学中,柯里化是一种将接受多个参数的函数,转换为一个函数序列,函数序列中的每个函数接受单个参数。示例:
function fn(a,b,c){
return a+b+c;
}
//正常执行
fn(1,2,3);
//柯里化之后:
fn(1)(2)(3);
- 函数柯里化的封装:
//传入一个函数作为参数
function curry(func) {
//形成闭包,将func函数传入到ruturn出去的函数中
return function curried(...args) {
//(...args)是剩余参数,该写法会将参数转化为数组的形式。
//详见:[MDN剩余参数](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Rest_parameters)
//判断args参数的长度 与 func函数的长度
if (args.length >= func.length) {
//若args>=func,直接return执行func
return func.apply(this, args); //此处使用apply是因为apply的第二个参数是数组的形式
} else {
//若args<func,return的新的函数,该函数递归执行curried函数。
return function (...args2) {
return curried.apply(this, args.concat(args2));
};
};
};
};
//用法
function sum(a, b, c) {
return a + b + c;
}
let curriedSum = curry(sum);
alert( curriedSum(1, 2, 3) ); // 6, 原传参形式调用正常
alert( curriedSum(1)(2,3) ); // 6, 柯里化第一个参数
alert( curriedSum(1)(2)(3) ); // 6, 全柯里化,也就是拆分所有参数
-
注意:
- 柯里化要求原函数具有固定数量的参数,即只适用于具有固定长度的函数
- 根据定义,柯里化后的函数只接受一个单一的参数,但是在js中,大多数的柯里化应用更灵活和高级。也就是说,柯里化后的函数不仅可以接受单个参数,也可以接受多个参数。
-
应用:
假设我们有一个记录(logging)函数
log(data,importance,message)
,该函数用于格式化和输出信息。如下:function log(data,importance,message){ alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`); }
柯里化该函数:
log = curry(log);
柯里化之后:
//可以和原函数一样调用 log(new Date(), "DEBUG", "some debug"); // log(a, b, c) //也可以柯里化调用 log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)
现在,我们可以为了方便,使用柯里化函数实现自动生成事件时间:
//logNow是 有固定第一个参数的log函数 let logNow = log(new Date()); letNow("info","message"); //[HH:mm] info message
更近一步,生成一个自动生成时间和debug的记录函数
let debugNow = logNow("Debug"); debugNow("message"); //[HH:mm] Debug message
意义:
- 使用柯里化函数之后,log函数依然可以正常调用
- 我么可以很容易的生成具有部分功能的函数,例如debugNow函数。
-
总结:
- 柯里化是一种函数形式转变,即从fn(a,b,c)转换为fn(a)(b)©。在js中应用柯里化函数中,既能保持原函数的正常调用,也能在参数数量不够的情况下返回部分函数。