JS函数式编程之柯里化
为什么要了解柯里化
柯里化是函数式编程必须要使用的. 这里我们就先介绍下什么是柯里化, 然后通过一个小例子体会柯里化的特点和使用方式.
什么是柯里化
curry 的概念很简单:只传递给函数一部分参数来调用它,让它返回一个函数去处
理剩下的参数。
你可以一次性地调用 curry 函数,也可以每次只传一个参数分多次调用。
[引自: js函数式编程指南]
小例子——两个数字相加函数的柯里化
// 非柯里化方式实现两个数相加的函数
function add(x, y) {
return x + y;
}
// 调用方式
var result = add(1, 2); // => 3
// 柯里化上面的求和函数, 即将两个参数的add函数改成传一个参数的函数
function curryAdd(x) {
return function(y) {
return x + y;
}
}
// 调用方式
var result = curryAdd(1)(2); // => 3
我们看到非柯里化方式实现的函数调用时,需要传递两个参数, 但是柯里化后, 传递第一个参数返回了一个函数, 返回的函数, 参数是之前的函数的第二个参数. 这样就保证了每个函数调用都传递一个参数.
既然结果一样, 柯里化后有什么好处呢?
如果我们有这样一个需求, 那柯里化就会派上用场. 我需要计算每个人的工资, 工资由基本工资和绩效工资组成. 每个人的基本工资一样, 但是他们的绩效工资不一样.用非柯里化的函数计算如下
// 假设基本工资是5000
// 员工a 绩效工资2000
var salaryA = add(5000, 2000);
// 员工b 绩效工资3000
var salaryB = add(5000, 3000);
用柯里化后的函数计算如下
// 创建一个缓存了基本工资的相加计算函数
var curryAddedX = curryAdd(5000);
// 计算员工a的工资
var salaryA = curryAddeX(2000);
// 计算员工b的工资
var salaryB = curryAddedY(3000);
用了柯里化后的函数计算, 就可以避免每次都传递5000这个基本工资了. 好处就是
- 减少了代码量
- 不用担心本该固定的值手误写错(在这里就是基本工资的值)
小例子——利用已有函数筛选数组中满足条件的元素
已有一个函数
// 第一个参数, 是否包含的字符串, 第二个参数是被检测的字符串
function isContain(smallStr, str) {
return str.indexOf(smallStr) !== -1;
}
使用数组的filter方法, 与上面的函数配合, 筛选出包含指定字符串的字符串
var arr = ['dog', 'cat', 'how are you'];
// 将isContain函数柯里化
function curryIsContain(smallStr) {
return function(str) {
return str.indexOf(smallStr) !== -1;
}
}
// 创建一个缓存了参数smallStr的筛选的函数, 用于筛选出含有空格的元素
var containSpace= curryIsContain(' ');
var result = arr.filter(containSpace);
// 创建一个用于筛选含有o的字符串
var containO = curryIsContain('o');
result = arr.filter(containO);
我们发现我们这里从新写了一个curryIsContain方法.
其实是用通用的办法把isContain转换成curryIsContain的.
这个办法就是: 柯里化函数. 我们来实现下他
// fn参数为将要被柯里化的函数, srcArgs参数为之前缓存的参数
function curry(fn, srcArgs) {
return function() {
var args = [].slice.apply(arguments);
var fullArgs = srcArgs === undefined ? args : srcArgs.concat(args);
if(fullArgs.length >= fn.length) {
return fn.apply(null, fullArgs);
} else {
return curry(fn, fullArgs);
}
}
}
我们用我们这个柯里化函数把isContain转换为curryIsContain
// 通过curry转换的curryIsContain具有同样的使用方式
var curryIsContain = curry(isContain);
提供柯里化的开源框架
总结
柯里化的函数, 拥有暂存部分参数, 延迟执行的能力. 直至所有的参数都提供完才执行有效功能代码.
如果我们刚好有个可用的多参函数FucntionMutiParams.
恰好另外一个地方, 需要使用函数FucntionMutiParams.
但是部分参数已经固定不需要改, 比如第一个例子中的固定工资.
或者有的地方只需要一个参数的函数. 事实上函数式编程的另外一个操作组合函数, 就需要只有一个参数的函数.
后面我们学习组合函数, 就会理解柯里化的必要性.
网友评论