1、 前言
之前一直听说过柯里化
不过一直没用过,最近在看闭包时提到闭包的一个用途之一就是柯里化
。正好来了解一下。
1.1 铺垫知识
虽然在实际项目中没见过这种写法fn(a)(b)(c)
(也有可能是我太菜没机会用到…),但是搜索柯里化相关的文章时,到处都是这种写法。
在看到这篇文章才知道,如果一个函数的返回值是另外一个函数,就可以用两个括号调用了。
1 2 3 4 5 6 7 8
| function fn(m) { return function (n) { return m + '与' + n + '前端学习'; } } let result = fn('小明')('小红'); console.log(result);
|
2、什么是柯里化 & 怎么实现柯里化
2.1 柯里化的概念
柯里化(Currying),又称部分求值(Partial Evaluation),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
文字看起来比较晦涩难懂,来一段代码简单粗暴的解释一下:
1 2 3 4 5 6 7 8 9
| function add(a, b, c) { return a + b + c; }
add(1,2,3)
curryAdd(1)(2)(3)
|
2.2 怎么实现柯里化
2.2.1 最简单的柯里化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function add(a, b, c) { return a + b + c; }
function addCurrying(a) { return function (b) { return function (c) { return a + b + c; } } }
add(1, 2, 3);
addCurrying(1)(2)(3)
|
被柯里化的函数 addCurrying 每次的返回值都为一个函数,并使用下一个参数作为形参,直到三个参数都被传入后,返回的最后一个函数内部执行求和操作,其实是充分的利用了闭包的特性来实现的。
2.2.2 封装通用的柯里化函数
上面的🌰太过死板,不具有通用性。我们需要再次封装一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function currying(func, args) { var arity = func.length; var args = args || []; return function () { var _args = [].slice.call(arguments); Array.prototype.unshift.apply(_args, args); if (_args.length < arity) { return currying.call(null, func, _args); } return func.apply(null, _args); } } function add(a, b, c) { return a + b + c; }
const aaa = currying(add); aaa(1)(2)(3)
|
上面的例子用了call
和apply
来改变this指向,代码有些冗余,下面用es6来重写一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function currying(func, args = []) { let arity = func.length; return function (..._args) { _args.unshift(...args); if (_args.length < arity) { return currying(func, _args); } return func(..._args); } } function add(a, b, c) { return a + b + c; } const aaa = currying(add); aaa(1)(2)(3)
|
3、 使用场景
3.1 参数复用
举个例子,你有一个商店🏠,你想给你的顾客 10% 的折扣:
1 2 3
| function discount(price, discount) { return price * discount }
|
当一个客户买了一件价值$500的商品,你会给他:
1
| const price = discount(500, 0.10); // $50
|
如果有其他客户分别买了价值$50,$60,$70的商品,那么则需要多次计算
1 2 3
| const price = discount(50, 0.10); // $5 const price = discount(60, 0.10); // $6 const price = discount(700, 0.10); // $7
|
柯里化一下这个折扣函数
1 2 3 4 5 6 7
| function curryDiscount(discount) { return function (price) { return price * 0.1; } } const tenPercentDiscount = curryDiscount(0.1);
|
3.2 延迟计算
// 暂时没找到示例
3.3 提前返回
// 暂时没找到示例
参考资料:
高阶函数应用 —— 柯里化与反柯里化
大佬,JavaScript 柯里化,了解一下?
JS中的柯里化(currying)
「译」理解JavaScript的柯里化
简述几个非常有用的柯里化函数使用场景