在计算机科学中,偏函数应用 是指将一些参数固定到一个函数,产生另外一个较小的函数的过程。javascript
举个例子:java
// 咱们建立了一个作 乘法运算 的函数
function mult(a, b) {
return a * b;
};复制代码
基于这个函数,咱们利用bind
创造一个新的函数 double
:编程
let double = mult.bind(null, 2);
console.log( double(3) ); // mult(2, 3) = 6;
console.log( double(4) ); // mult(2, 4) = 8;
console.log( double(5) ); // mult(2, 5) = 10; 复制代码
mult.bind(null, 2)
创造了一个新函数 double
,传递调用到mult
函数,以null
为context
,2
为第一个参数。其余参数等待传入。api
这就是 偏函数应用 —— 咱们创造了一个新函数,同时将部分参数替换成特定值。app
刚刚咱们基于mult
建立了一个新的函数double
,这里咱们再建立一个新的函数triple
:编程语言
let triple = mult.bind(null, 3);
console.log( triple(3) ); // mult(3, 3) = 9;
console.log( triple(4) ); // mult(3, 4) = 12;
console.log( triple(5) ); // mult(3, 5) = 15;复制代码
使用 偏函数,咱们可以从中受益的是:咱们建立了一个独立的非匿名函数(double
,triple
)。咱们可使用它,而不须要每次都传入第一个参数,由于bind
帮咱们搞定了。函数式编程
在其余的场景中,当咱们有一个很是通用的函数,而且想要方便地获取它的特定变体,偏函数也是很是有用。函数
举个例子,咱们拥有函数post(signature, api, data)
。在调用请求方法的时候有着相同的用户签名,这里咱们想要使用它的偏函数变体:post(api, data)
,代表该请求发送自同一用户签名。post
有时候人们会把 偏函数应用 和另一个名为 柯里化 的东西混淆,但那的确是另一个和函数有关的有趣技术。ui
在 函数式编程语言 和 其余许多语言 中,柯里化(currying)提供了一种自动管理参数如何传递给函数和异常的方法。
简单来讲,currying
是一项将一个调用形式为f(a, b, c)
的函数转化为调用形式f(a)(b)(c)
的技术。
举个例子:
function currying(fn) {
return function(a) {
return function(b) {
return fn(a, b);
};
};
}
// 用法
function sum(a + b) {
return a + b;
}
let carriedSum = currying(sum);
console.log( carriedSum(1)(2) ); // 3复制代码
从上面的例子能够看到,carrying
的实现就是一系列的封装。
currying(fn)
的结果就是一层封装function(a)
。carriedSum(1)
这样,它的参数被保存到 词法环境 中,而后返回一层新的封装function(b)
。carriedSum(1)(2)
调用function(b)
,传入参数2
,它将调用传递给初始的多参数函数sum
。结合以前的 偏函数 知识,咱们能够看到,sum
函数在 柯里化 以后,逐个传递参数的时候返回的那一层封装:其实就是 sum
函数 的 偏函数变体。
这可能也是你们容易将这个两个概念搞混的缘由之一吧。
高级的柯里化同时容许 函数正常调用 和 获取偏函数。
咱们能够实现一下 高级的柯里化:
function currying(fn) {
return function curried(...args) {
if(args.length>=fn.length) {
// 传入的实参长度 >= 初始函数形参长度 的时候,则直接执行初始函数
return fn.apply(this, args);
} else {
// 不然 获得一个 偏函数,递归carried方法,直到得到全部参数后,直接执行
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
}
}
function sum(a, b, c) {
return a + b + c;
}
let curriedSum = currying(sum);
// 常规调用
console.log( curriedSum(1, 2, 3) ); // 6
// 获得 curriedSum(1)的偏函数,而后用另外两个参数调用它
console.log( curriedSum(1)(2, 3) ); // 6
// 彻底柯里化调用
console.log( curriedSum(1)(2)(3) ); // 6复制代码
从上面的 高级柯里化 实现的例子中能够发现:
sum
函数 在 柯里化 以后对于使用并无任何影响,仍然能够被正常调用。总得来讲,柯里化的目的 就是在不影响 初始函数 的调用形式的状况下,更方便的让咱们得到初始函数的 偏函数 变体。
最后,欢迎各位小伙伴留言,相互讨论。