前言
(话不多说,填之前的坑)
正文
引子-从apply说函数应用
在js里,我们对于function的用法,可能大部分情况下都还是处于调用,形如
function add(x, y) {
return x + y
}
console.log(add(1, 2)) //函数调用 返回3
但是有一个apply()
函数,使我们拥有另一种方式来应用函数,例如
function add(x, y) {
return x + y
}
console.log(add.apply(null, [1, 2])) //返回3
apply
的第一个参数为null
时,this
指向全局对象(忘记请自行查阅查mdn),在上面这个例子里,通过apply
来应用函数的时候,效果和调用函数完全一致。
部分应用
从前文可知,函数调用就是让一个参数集合(前面的[1,2])应用到函数(前文的add函数)中,那部分应用就是考虑只传递部分参数,而非所有参数。 还是上面add
函数的例子,我们希望实现下面的形式(在下一节具体实现):
var newAdd = add.apply(null,[1])//部分应用 只传递了第一个参数
newAdd.apply(null,[2]) //3
分析上面的代码可知,实现部分应用的关键是:部分应用的返回结果是一个新的函数,该函数可以被传入其他参数再次调用
柯里化(curry)
现在进入正题,前面讲完了部分应用
。curry化的含义,就是使函数理解并处理部分应用的过程
继续按照上文的思路实现add
函数的curry化:
function add(x, y) {
// 如果只传递部分参数,则部分应用,返回一个新的函数
if (y === undefined) {
return function (y) {
return x + y
}
}
return x + y //如果传递所有参数,直接完全应用
}
//运行前一节代码
var newAdd = add.apply(null, [1])
console.log(newAdd.apply(null, [2])) //3
console.log(newAdd.apply(null, [5])) //6
上述代码已经实现了前一节的要求,可以看到curry的结果就是:经过一次curry的newadd
函数,变成一个与1求和的函数,接应用的时候只传递一个参数,都能得到对应的结果,同时也可以看出这个curry太局限。接下来我们就要考虑,如何实现通用的curry函数
通用curry函数
先回忆前面的过程,来思考curry一个函数的实现步骤:
- 保存调用curry函数时传入的参数,返回一个新函数(即柯里化执行结果)
- 结果函数在被调用后,要让新的参数和旧的参数一起应用的入参函数中
注:入参函数-要被curry的函数,结果函数-被curry之后的函数*
文字比较抽象,可以直接看实现在回来看过程:
function commonCurry(fn) {
var slice = Array.prototype.slice,
storedArgs = slice.call(arguments, 1) //使用slice是为了把arguments转换成真正的数组,剥离此处第一个参数,是因为第一个参数是fn
return function () {
var newArgs = slice.call(arguments), //新传入的参数
args = storedArgs.concat(newArgs)
return fn.apply(null, args)
}
}
//使用举例
function add(a, b) {
return a + b
}
var newAdd = commonCurry(add, 10)
console.log(newAdd(5))
// 多个参数
function add2(a, b, c, d) {
return a + b + c + d
}
var newAdd2 = commonCurry(add2, 10, 10)
console.log(newAdd2(5, 4))//29
// 多次curry
var newAdd3 = commonCurry(newAdd2, 10)
console.log(newAdd3(10))//40
小结
之后会尝试以更简洁明了的方式来写文章。如果内容有错误的地方欢迎指出(觉得看着不理解不舒服想吐槽也完全没问题);如果对你有帮助,欢迎点赞和收藏,转载请征得同意后著明出处,如果有问题也欢迎私信交流,主页添加了邮箱地址。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。