定义
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
举例
//未柯里化的函数
function add(x, y, z) {
return x + y + z;
}
var result = add(10, 20, 30);
console.log(result); //60
//柯里化后的函数
function sum1(x) {
return function(y) {
return function(z) {
return x + y + z
}
}
}
var result1 = sum1(10)(20)(30)
console.log(result1); //60
//简化柯里化函数的代码
var sum2 = x => y => z => {
return x + y + z
}
console.log(sum2(10)(20)(30)); //60
var sum3 = x => y => z => x + y + z;
console.log(sum3(10)(20)(30)); //60
柯里化的作用
让函数的职责单一
在函数式编程中,我们往往希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理逻辑交给一个 函数来处理。 那么我们是否就可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结果。
举例
function sum(x) {
x = x + 2
return function(y) {
y = y * 2
return function(z) {
z = z * z
return x + y + z
}
}
}
console.log(sum(10)(20)(30)) //952
复用参数逻辑
//adder函数传入num(num可进行一些修改),在之后使用返回的函数时,不需要再传入num了
function adder(count) {
count = count + 1;
return function(n) {
return count + n;
}
}
var add = adder(5)
add(10); //16
add(15); //21
add(20); //26
打印日志的柯里化
我们演示一个案例,需求是打印一些日志。要求能够打印不同日期的日志,能够区分日志类型(debug、release、error)。按照预期,我们设计一个函数,应该有三个参数,日期、日志类型、日志内容。
一般设计
function log(date, type, message) {
console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]: [${message}]`)
}
log(new Date(), "debug", "debug模式的日志")
log(new Date(), "release", "release模式的日志")
log(new Date(), "error", "数据的error")
柯里化优化设计
// 柯里化的优化
var log = date => type => message => {
console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]: [${message}]`)
}
//如果我现在打印的都是当前时间日志
var nowLog = log(new Date())
nowLog("debug")("当前时间,debug模式的日志")
nowLog("release")("当前时间,release模式的日志")
//如果我们打印,当前时间debug模式下的日志
var nowAndDebugLog = log(new Date())("debug")
nowAndDebugLog("日志1")
nowAndDebugLog("日志2")
柯里化函数的简单实现
将一个多参数普通函数转为柯里化函数
//普通函数
function add(x, y, z) {
return x + y + z
}
//柯里化函数
function myCurrying(fn) {
function curried(...args) {
//判断柯里化后的函数传入的参数与原函数的关系
//如果柯里化后的函数传入的参数 >= 原函数的参数,那就执行原函数
if (args.length >= fn.length) {
//return fn(...args) //不建议用这种方式调用函数
//return fn.call(this, ...args) //建议用这种方式调用函数保证this指向
return fn.apply(this, args) ////建议用这种方式调用函数保证this指向
} else {
// 柯里化后的函数参数没有达到个数时, 需要返回一个新的函数, 继续来接收的参数
function curried2(...args2) {
// 接收到参数后, 需要递归调用curried来检查函数的个数是否达到
return curried.apply(this, args.concat(args2))
}
return curried2
}
}
return curried
}
//将普通函数柯里化
var curryAdd = myCurrying(add)
//测试
console.log(curryAdd(10, 20, 30))
console.log(curryAdd(10, 20)(30))
console.log(curryAdd(10)(20)(30))