函数柯里化是什么
很简单,只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
你可以一次性地调用 curry 函数,也可以每次只传一个参数分多次调用。
var add = function(x) {
return function(y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
console.log(increment(2));
// 3
console.log(addTen(2));
// 12
柯里化其实通过闭包的方式记住了add的第一个参数x
,这样第二次调用时就有了x这个参数。
函数柯里化能做什么
在学习的时候,看到了一个很合适很喜欢的例子。
我们要做一个用于格式化和输出信息的日志(logging)函数 log(date, importance, message)
。在实际项目中,此类函数具有很多有用的功能,例如通过网络发送日志(log),在这儿我们仅使用console.log
function log(date, importance, message) {
console.log(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}
如果不自己手写柯里化,可以使用库。柯里化更高级的实现,例如 lodash 库的 _.curry,会返回一个包装器,该包装器允许函数被正常调用或者以偏函数(partial)的方式调用
参考:https://zh.javascript.info/currying-partials
function sum(a, b) {
return a + b;
}
let curriedSum = _.curry(sum); // 使用来自 lodash 库的 _.curry
alert( curriedSum(1, 2) ); // 3,仍可正常调用
alert( curriedSum(1)(2) ); // 3,以偏函数的方式调用
这里我们试试自己手写柯里化:
function log(date){
return function (importance){
return function (message) {
console.log(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}
}
}
// 柯里化方式执行函数
log(new Date())("DEBUG")("some debug") // [14:50] [DEBUG] some debug
但现在这样调用的方式并不是我们所喜欢的,所以进一步添加代码
let logNow = log(new Date())
let logDebug = logNow("DEBUG")
let logInfo = logNow("INFO")
let logWarning = logNow("WARNING")
logDebug('some debug') // [14:50] [DEBUG] some debug
logInfo('some info') // [14:54] [INFO] some info
logWarning('some warning') // [14:54] [WARNING] some warning
看到这里是不是开始觉得有些熟悉了?
总结:其实函数柯里化算是个很简单的概念,或许我们每天都在使用。看上面的代码就能发现,这个过程就像我们封装一些通用组件时的过程。
柯里化 是一种转换,将
f(a,b,c)
转换为可以被以f(a)(b)(c)
的形式进行调用。JavaScript 实现通常都保持该函数可以被正常调用,并且如果参数数量不足,则返回偏函数。
柯里化让我们能够更容易地获取偏函数。就像我们在日志记录示例中看到的那样,普通函数log(date, importance, message)
在被柯里化之后,当我们调用它的时候传入一个参数(如log(date)
)或两个参数(log(date, importance)
)时,它会返回偏函数。
参考:https://zh.javascript.info/currying-partials