柯里化和偏函数
柯里化(Currying)
柯里化是一种与函数相关的高级技巧,不仅仅被用于 JS,也被用于其他语言。我们直接引用 Wiki 百科中 Currying 的概念
currying is the technique of converting a function that takes multiple arguments into a sequence of functions that each take a single argument. For example, currying a function
f
that takes three arguments creates three functions:
看图也很好理解了,柯里化是将一个多参数函数转换为多个拥有单个参数函数的过程,比如
// 假设存在 curry 函数能提供柯里化
function getSum(a, b, c) {
return a + b + c
}
let fn = curry(getSum)
fn(1) // return a function
fn(3) // return a function
fn(4) // return 8
// 或者
fn(1)(3)(4) // 8
curry 函数实现
根据柯里化的定义,curry 函数接受一个函数返回一个函数,函数又会返回一个函数,直到接受的参数满足原函数形参数目为止,才会执行原函数。 我们知道函数的 length 属性指明函数的形参个数。
我们需要先将传入的参数先收集起来,在参数数目数满足条件的时候,再将实参传入原函数执行。在参数不够的时候,我们将参数传递下去。
于是我们可以先写出下面的代码
function curry(func) {
// 函数能够接受的参数个数
const len = func.length;
function curried(...rest){
if(rest.length >= len){
return func(...rest);
}else{
return (...arg) => {
curried(...rest, ...arg)
}
}
}
return curried;
}
为了在函数运行时绑定 this,我们将代码稍微做下调整
function curry(func) {
// 函数能够接受的参数个数
const len = func.length;
function curried(...rest){
if(rest.length >= len){
return func.apply(this, rest);
}else{
return curried.bind(this, ...rest)
}
}
return curried;
}
偏函数(partial application)
再来看看偏函数的定义
partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.
arity 可以理解为函数需要提供的 arguments 或者需要操作的对象的个数
那偏函数就指的是将参数固定在一个函数中,从而返回一个 arguments 更小的函数
// 假设存在 partial 函数能够返回一个偏函数
function getSum(a, b, c) {
return a + b + c
}
let fn = partial(getSum, 1)
fn(3, 4) // 8
偏函数实现
可以发现偏函数实现与 curry 实现非常相似,在 curry 函数的基础上,允许先绑定一些参数,后续调用返回函数的时候,不用重复填写参数。
我们将原先固定的实参,与后续调用传入的实参合并为一个数组,与原函数的 length 做比较。
function partial(func, ...rest){
const len = func.length;
function returnFn(...arg){
// 实际的参数
const realityArg = rest.concat(arg);
if(realityArg.length >= len){
return func.apply(this, realityArg)
}else {
return returnFn.bind(this, ...realityArg)
}
}
return returnFn;
}