JavaScript 函数式编程中的 curry 实现

最近在 学习javascript 函数式编程,对其中大名鼎鼎的curry 十分感兴趣, curry 函数可以接受一个函数,我们暂且称之为原始函数,返回的也是一个函数,柯里化函数,这个返回的柯里化函数功能十分强大,他在执行的过程中,不断的返回一个贮存了传入参数的函数,直到触发了原始函数执行的条件。这么说比较概括,那么就举个例子来说明一下:
  原始函数:
  var add = (x, y) => x + y
  柯里化函数:
   var curryAdd = curry(add)
  这个add 需要两个参数,但是我们的 curryAdd 执行可以传入更少的参数,当传入的参数少于 add 需要的参数的时候, add 函数并不会执行, curryAdd 就会将这个参数记下来,并且返回另外一个函数,这个函数可以继续执行传入参数,我们会有一个变量专门记录传入参数的情况,如果传入参数的总数等于 add 需要参数的总数,我们就激活了原始参数执行,就会返回我们想要的结果。
  //  此时只传入了一个参数 根据判断返回的是一个函数
   var add2 = curryAdd(2)
  // add2 = function(...) {}
  //  此时累计传入了两个参数 等于了 add 需要参数的总和 所以返回的是一个结果
  //  相当于执行了 add(2)(3)
   var result = add2(3)
  // result = 5
  还是很不错的是吧,好吧,我们的目的是为了写出这个神奇curry 函数,而且还要一行写出来,不要着急,先分析一下怎么去写,然后再一步步的优化。
  那根据上面的描述,我们看一下curry 函数需要什么,首先需要一个变量,用来存下来原始函数的参数个数,我们知道 function 有一个属性为 length ,对就是它,我们用 limit 存下来
   var curry =  function(fn) {
   var limit = fn.length
  ...
  }
  curry 函数要返回一个函数 这个函数是要执行的,那么问题就是,我们要判断这个函数的执行是否激活了原始函数的执行,问题就出现在传入的参数上面。返回函数还是结果?这的确是一个问题,我们先写返回结果的情况,当传入的参数等于原始函数需要的参数时,我们执行原始函数 fn
   var curry =  function(fn) {
   var limit = fn.length
   return  function (...args) {
   if (args.length >= limit) {
   return fn.apply( null, args)
  }
  }
  }
  否则呢  我们就要返回一个贮存了参数的函数,这里有两点,一是参数的传入历史我们要记录下来,二是这个返回的函数需要做些什么
   var curry =  function(fn) {
   var limit = fn.length
   return  function (...args) {
   if (args.length >= limit) {
   return fn.apply( null, args)
  else {
   return  function(...args2) {
  }
  }
  }
  }
  看出来了吧  我们只需要把返回函数执行的参数累加起来就达到了记录参数传入情况的目的,于是我们想到了concat  args.concat(args2),  依次类推,我们返回的函数要做的就是重复做上面的事情,也就是参数为 args 的函数要做的事情,所以他需要一个名字,不然我们没法执行,我们叫它 judgeCurry
  所以正如我们所说的,要么返回一个函数,要么执行原始函数。
   var curry =  function(fn) {
   var limit = fn.length
   return  function  judgeCurry (...args) {
   if (args.length >= limit) {
   return fn.apply( null, args)
  else {
   return  function(...args2) {
   return judgeCurry.apply( null, args.concat(args2))
  }
  }
  }
  }
  我们终于写完了这个神奇的curry 函数,它真的很强大,配合 compose ,那真是一个字,爽。
  我们的目的还是一行把上面那个函数写出来,一行写?怎么写?对了,用ES6 啊,于是一番折腾
  var currySingle = fn => judgeCurry = (...args) => args.length >= fn.length ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2))
  好,我们看一下哪有问题,对了,就是我们为了不用limit 参数,用了就得赋值,赋值就不能一行搞定了,就会变成这样
   var currySingle = fn => {
   var limit = fn.length
   var judgeCurry =  null
   return judgeCurry = (...args) => args.length >= limit ? fn.apply( null, args) : (...args2) => judgeCurry.apply( null, args.concat(args2))
  }
  需要判断参数的时候不断的对fn.length 求值,但是 fn.length 的值是确定的,我们不想每次都求值,但又不想用 limit 怎么办,有什么办法呢?你一定想到了,立即执行函数!!
  var currySingle = fn => ((limit) => judgeCurry = (...args) => args.length >= limit ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2)))(fn.length)
  不得不感叹javascript 的神奇,终于,我们就一行将这个神奇的 curry 写出来了。
来源:码农网
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值