什么是函数柯里化?
- 百度百科:在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
- 通俗点说就是将一个函数拆分成多个函数,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数。
需求:分步计算四个数字的相加
function add(a, b, c, d) {
return a + b + c + d;
}
// 参数柯里化
function FixedParmasCurry(fn) {
let _arg = [].slice.call(arguments, 1) // 第一次获得参数
return function () { // 返回新的函数
let newArg = _arg.concat([].slice.call(arguments, 0)) // 参数合并
return fn.apply(this, newArg); // 执行函数
}
}
var newAdd = FixedParmasCurry(add,2,3);
console.log(newAdd(2,3)) // 10
- 问题: 以上代码只是实现了两步的相加,没有真正实现柯里化
- 实现 add(2)(3)(1)(4) 模式代码
function add(a, b, c, d) {
return a + b + c + d;
}
function FixedParmasCurry(fn) {
let _arg = [].slice.call(arguments, 1)
return function () {
let newArg = _arg.concat([].slice.call(arguments, 0))
return fn.apply(this, newArg);
}
}
function Curry(fn, length) {
// 获得函数的参数剩余长度
length = length || fn.length;
return function () {
if (arguments.length < length) { // 参数不足
let combined = [fn].concat([].slice.call(arguments, 0)) // [fn,1] [fn,2] ...
return Curry(FixedParmasCurry.apply(this, combined), length - arguments.length) // 递归
} else {
return fn.apply(this, arguments)
}
}
}
let newAdd = Curry(add);
let res = newAdd(1)(2)(3)(4)
console.log(res); // 10
关于curry的一些性能问题
- 存取arguments对象通常要比存取命名参数要慢一点
- 使用
fn.apply
通常比直接调用稍微慢点 - 创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上
- 不过对于这些,js的性能损耗基本是可以忽略不计的,所以curry是可以直接放心的使用。