function curry(func) { return function curried(...args) { if (args.length >= func.length) { return func.apply(this, args); } else { return function(...args2) { return curried.apply(this, args.concat(args2)); } } }; } function sum(a, b, c) { return a + b + c; } let curriedSum = curry(sum); // still callable normally alert( curriedSum(1, 2, 3) ); // 6 // get the partial with curried(1) and call it with 2 other arguments alert( curriedSum(1)(2,3) ); // 6
这里实现看上去有点复杂,但确实很容易理解。curry(func)的结果是包装器curried,如下所示:
// func is the function to transform function curried(...args) { if (args.length >= func.length) { // (1) return func.apply(this, args); } else { return function pass(...args2) { // (2) return curried.apply(this, args.concat(args2)); } } };
当我们运行时,有两个分支:
1. 如果传递args数与原函数已经定义的参数个数一样或更长,那么直接调用。
2. 获得偏函数:否则,不调用func函数,返回另一个包装器pass,提供连接之前的参数一起做为新参数重新应用curried。然后再次执行一个新调用,返回一个新偏函数(如果参数不够)或最终结果。
举例,让我们看sum(a, b, c)会怎样,三个参数,所以sum.length=3.
如果调用curried(1)(2)(3):
1. 第一次调用curried(1),在词法环境中记住1,返回包装器pass。
2. 使用(2)调用包装器pass:其带着前面的参数(1),连接他们然后调用curried(1,2),因为参数数量仍然小于3,返回pass。
3. 再次使用(3)被调用包装器pass,带着之前的参数(1,2),然后增加3,并调用curried(1,2,3)——最终有三个参数,传递给原始函数。
如果仍然不清除,可以按顺序在脑子里或纸上跟踪调用过程。
仅针对函数参数长度固定
柯里化需要函数有已知的参数数量固定。
比柯里化多一点
根据柯里化定义,转换sum(a,b,c)至sum(a)(b)(c).
但在Javascript中大多数实现是超越定义,也可以让函数使用多个参数变量执行。
总结
当把已知函数的一些参数固定,结果函数被称为偏函数,通过使用bind获得偏函数,也有其他方式实现。
当我们不想一次一次重复相同的参数时,偏函数是很便捷的。如我们有send(from,to)函数,如果from总是相同的,可以使用偏函数简化调用。
柯里化是转换函数调用从f(a,b,c)至f(a)(b)(c).Javascript通常既实现正常调用,也实现参数数量不足时的偏函数方式调用。
当我们想容易的偏函数时,柯里化非常好。如我们已经看到的日志示例:通用的函数是log(date,importance,message),柯里化之后获得偏函数为,一个参数如log(date),或两个参数log(date,importance).
更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》