一行写出javascript函数式编程中的curry

最近在学习javascript函数式编程,对其中大名鼎鼎的curry十分感兴趣,curry函数能够接受一个函数,咱们暂且称之为原始函数,返回的也是一个函数,柯里化函数,这个返回的柯里化函数功能十分强大,他在执行的过程当中,不断的返回一个贮存了传入参数的函数,直到触发了原始函数执行的条件。这么说比较归纳,那么就举个例子来讲明一下:javascript

原始函数:java

var add = (x, y) => x + y

柯里化函数:编程

var curryAdd = curry(add)

这个add须要两个参数,可是咱们的curryAdd执行能够传入更少的参数,当传入的参数少于add须要的参数的时候,add函数并不会执行,curryAdd就会将这个参数记下来,而且返回另一个函数,这个函数能够继续执行传入参数,咱们会有一个变量专门记录传入参数的状况,若是传入参数的总数等于add须要参数的总数,咱们就激活了原始参数执行,就会返回咱们想要的结果。app

// 此时只传入了一个参数 根据判断返回的是一个函数
    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
因此正如咱们所说的,要么返回一个函数,要么执行原始函数。code

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啊,因而一番折腾ip

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写出来了。。。

相关文章
相关标签/搜索