柯里化
也是属于函数式编程里面一个非常重要的概念。
我们先来看一下维基百科的解释:
- 在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化;
- 是把
接收多个参数的函数
,变成接受一个单一参数(最初函数的第一个参数)的函数
,并且返回接受余下的参数
,而且返回结果的新函数的技术
; - 柯里化声称 “
如果你固定某些参数,你将得到接受余下参数的一个函数
”;
维基百科的结束非常的抽象,我们这里做一个总结:
- 只传递给函数
一部分参数
来调用它,让它返回一个函数去处理剩余的参数
; - 这个过程就称之为
柯里化
;
柯里化的结构
//下面把add函数转换为sum函数的过程就叫柯里化
function add(x, y, z) {
return x + y + z;
}
var result = add(10, 20, 30);
console.log(result); //60
//把add函数进行柯里化
function sum(x) {
return function (y) {
return function (z) {
return x + y + y;
};
};
}
var result1 = sum(10)(20)(30);
console.log(result1);
//简化柯里化的代码
var sum2 = x => y => z => x + y + z
柯里化的作用
1.让函数的职责单一
那么为什么需要有柯里化呢?
- 在函数式编程中,我们其实往往希望
一个函数处理的问题尽可能的单一
,而不是将一大堆的处理过程交给一个函数来处理
; - 那么我们是否就可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结 果;
比如上面的案例我们进行一个修改:传入的函数需要分别被进行如下处理
- 第一个参数 + 2
- 第二个参数 * 2
- 第三个参数 ** 2
function add(x, y, z) {
x = x + 2;
y = y * 2;
z = z ** 2;
return x + y + z;
}
console.log(add(10, 20, 30));
function sum(x) {
x = x + 2;
return function (y) {
y = y * 2;
return function (x) {
z = z ** 2;
return x + y + z;
};
};
}
console.log(sum(10)(20)(30));
2.柯里化的复用
另外一个使用柯里化的场景是可以帮助我们可以复用参数逻辑:
- makeAdder函数要求我们传入一个count(并且如果我们需要的话,可以在这里对num进行一些修改);
- 在之后使用返回的函数时,我们不需要再继续传入count了;
function sum(num1, num2) {
return num1 + num2
}
//如果需要多次把一个数字和5相加,求值
sum(5, 10)
sum(5, 15)
sum(5, 88)
sum(5, 120)
//使用柯里化
function makeAdder(count) {
return function(num) {
return count + num
}
}
var add5 = makeAdder(5)//这一段逻辑被复用
add5(10)
add5(15)
add5(88)
add5(120)
3.打印日志的柯里化
这里我们在演示一个案例,需求是打印一些日志:
- 日志包括时间、类型、信息;
//打印日志的柯里化
function log(date, type, message) {
console.log(`[${date.getHours()}:${date.getMinutes()}]:[${type}]:[${message}]`)
}
//每次都需要输入时间,类型,信息,即使时间一样
log(new Date(), "DEBUG", "查询轮播图的bug")
log(new Date(), "DEBUG", "查询菜单的bug")
log(new Date(), "DEBUG", "查询列表的bug")
var log1 = date => type => message => {
console.log(`[${date.getHours()}:${date.getMinutes()}]:[${type}]:[${message}]`)
}
//如果我现在打印的都是当前时间,
var nowLog = log1(new Date())
//只需要输入类型和信息
nowLog("DEBUG", "查询轮播图的bug")
nowLog("FETURE", "添加了新用户功能")
nowLog("FIX", "修复了菜单问题")
//如果我现在打印的都是当前时间的bug
var nowDebugLog = log1(new Date())("DEBUG")
//只需要输入信息
nowDebugLog("查询轮播图的bug")
nowDebugLog("查询菜单的bug")
nowDebugLog("查询列表的bug")
自动柯里化函数
需求:传入一个普通函数,返回一个新的函数,是传入的函数的柯里化函数
function curry(fn) {
}
//满足下面功能
function add(x, y, z) {
return x + y + z;
}
const curryAdd = curry(add);
console.log(curryAdd(10, 20, 30)); //60
console.log(curryAdd(10, 20)(30)); //60
console.log(curryAdd(10)(20, 30)); //60
console.log(curryAdd(10)(20)(30)); //60
实现
//需求:传入一个普通函数,返回一个新的函数,是传入的函数的柯里化函数
function curry(fn) {
return function proxy(...args) {
//通过fn.length获取到fn的形参个数
//假如传给proxy函数的实参个数大于等于fn的形参个数,说明已经传入了所有的参数
if (args.length >= fn.length) {
//直接调用fn即可,但需要保证proxy函数上下文的this和fn的this保持一致,并返回执行结果
return fn.apply(this, args);
} else {
return function proxy2(...params) {
return proxy.call(this, ...args.concat(params));
};
}
};
}
非常感谢王红元老师的深入JavaScript高级语法让我学习到很多 JavaScript
的知识
网友评论