JS函数柯里化 学习笔记

函数柯里化是一个比较重要的JS特性,在笔试题和面试题中都出现过,现在把它学习一下。

函数柯里化是函数式编程里面的概念:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。

主要是体现在从函数里返回函数,将一个传递多个变量的函数调用改成了传递单个变量的多个函数调用。

举个经典例子,把f(1,2,3)变成f(1)(2)(3)

柯里化有 3 个常见应用:

  • 参数复用:需要多次调用同一个函数,并且传递的参数绝大多数是相同的,使用柯里化就很合适
  • 提前返回:多次调用多次内部判断,可以直接把第一次判断的结果返回外部接收
  • 延迟计算:避免重复执行程序,等真正需要结果的时候再执行

提前返回和延迟计算其实是一回事,因为执行柯里化函数的的过程当中返回的是执行了一部分的函数,没有直接返回结果,所以叫提前返回,同时,直到所有参数传递完成才会执行计算,所以叫延迟计算。

这个方法如果自己硬写的话,其实很直观,return里继续return一个function就可以,无限套娃。

但对于经典的面试题累加函数来说,有没有一个能接收无限个数参数的方法?当然有。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function add() {
// 首先将传入的arguments(参数表)转为数组对象
let args = Array.prototype.slice.call(arguments);

// 使用递归完成操作
// 当 add 函数不断调用时,把第 N+1 个括号的参数加入到第 N 个括号的参数里面
let inner = function() {
args.push(...arguments);
return inner;
}

inner.toString = function() {
// 每次拿到inner时,参数会随着传入的数量不断增加,此时使用reduce依次累加即可
return args.reduce(function(prev, cur) {
return prev + cur;
});
};

return inner;
}

// 需要注意,result是一个函数类型,我们重写了toString用于返回它的值
let result = add(1)(2)(3)(4);
console.log(result.toString());

arguments不是数组,不能使用数组的操作,需要首先将其拆分成数组。每次执行add函数的时候,返回的函数都是inner函数。

如果直接打印result,不重写toString,会发现result是一个函数类型,原本的函数变成字符串返回了,所以这里还需要重写一下toString,然后在输出时使用它,即可获得结果。

那下面的问题来了,如果面试官出的不是这个累加呢?有没有更通用的办法?

其实直接用上面这个改进也可以,但也有更优雅的写法。要判断当前传入的函数参数个数是否大于等于原函数所需参数个数,使用函数名.length可以访问,如果是,则执行此函数,如果小于,那么返回一个函数,递归继续处理。

1
2
3
4
5
6
7
const curry = (fn, ...args) => args.length >= fn.length ? fn(...args) : (..._args) => curry(fn, ...args, ..._args);

function add1(x, y, z) {
return x + y + z;
}
const add = curry(add1);
console.log(add(1, 2, 3));

很优雅吗?是的,很优雅,一行搞定。

还搞不了?实在不行……上lodash吧。

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2023 Shawn Zhou
  • Hexo 框架强力驱动 | 主题 - Ayer
  • 访问人数: | 浏览次数:

感谢打赏~

支付宝
微信