首页 > 语言 > JavaScript > 正文

深入剖析JavaScript中的函数currying柯里化

2024-05-06 14:58:53
字体:
来源:转载
供稿:网友

curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名)。
 
柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果。

因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程。 

柯里化一个求和函数
按照分步求值,我们看一个简单的例子

var concat3Words = function (a, b, c) {   return a+b+c; };  var concat3WordsCurrying = function(a) {   return function (b) {     return function (c) {       return a+b+c;     };   }; }; console.log(concat3Words("foo ","bar ","baza"));      // foo bar baza console.log(concat3WordsCurrying("foo "));         // [Function] console.log(concat3WordsCurrying("foo ")("bar ")("baza")); // foo bar baza 

可以看到, concat3WordsCurrying("foo ") 是一个 Function,每次调用都返回一个新的函数,该函数接受另一个调用,然后又返回一个新的函数,直至最后返回结果,分布求解,层层递进。(PS:这里利用了闭包的特点) 
 

那么现在我们更进一步,如果要求可传递的参数不止3个,可以传任意多个参数,当不传参数时输出结果? 

首先来个普通的实现:

var add = function(items){   return items.reduce(function(a,b){     return a+b   }); }; console.log(add([1,2,3,4])); 

但如果要求把每个数乘以10之后再相加,那么:

var add = function (items,multi) {   return items.map(function (item) {     return item*multi;   }).reduce(function (a, b) {     return a + b   }); }; console.log(add([1, 2, 3, 4],10)); 

好在有 map 和 reduce 函数,假如按照这个模式,现在要把每项加1,再汇总,那么我们需要更换map中的函数。 

下面看一下柯里化实现:

var adder = function () {   var _args = [];   return function () {     if (arguments.length === 0) {       return _args.reduce(function (a, b) {         return a + b;       });     }     [].push.apply(_args, [].slice.call(arguments));     return arguments.callee;   } };   var sum = adder();  console.log(sum);   // Function  sum(100,200)(300);  // 调用形式灵活,一次调用可输入一个或者多个参数,并且支持链式调用 sum(400); console.log(sum());  // 1000 (加总计算) 

上面 adder是柯里化了的函数,它返回一个新的函数,新的函数接收可分批次接受新的参数,延迟到最后一次计算。 
 

通用的柯里化函数

更典型的柯里化会把最后一次的计算封装进一个函数中,再把这个函数作为参数传入柯里化函数,这样即清晰,又灵活。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选