js函数式编程-函数合成和柯里化

函数式编程有2个最基本的运算:合成(compose)和柯里化(currying)

 

合成:如果一个值要经过多个函数才能编程另一个值,那么我们可以把中间的步骤合并成一个函数,这个叫做函数的合成

函数的合成我们采用es6的reduce方法,先举一个小例子说明reduce的特性

const arr = [1,2,3,4]
let a = arr.reduce(function(total,next){
    return total+next
})
console.log(a) //10

可以看到,reduce接收一个函数,函数的两个参数分别代表了累加返回值和下一个要处理的值,我们用reduce最多的场景是用它来求和。那么如果我们把arr数组换成函数数组,在reduce里一层一层的执行函数不就可以实现函数的合成了嘛。

下面我们把上边的数字组成的数组换成函数组成的数组,再用一个函数包装一下reduce函数

function f1(arg){
    console.log("f1",arg)
    return arg;
}
function f2(arg){
    console.log("f2",arg)
    return arg;
}
function f3(arg){
    console.log("f3",arg)
    return arg;
}
function compose(...funcs){
    if(funcs.length===0){
        return arg=>arg;
    }
    if(funcs.length===1){
        return funcs[0];
    }
    // return funcs.reduce((a,b)=>(...args)=>a(b(...args)))
    return funcs.reduce(function(a,b){
        return function(o){
            return a(b(o))
        }
    })
}
let res = compose(f1,f2,f3)("omg");//f1(f2(f3("omg"))) 洋葱模型
console.log("res",res);

打印结果:

f3 omg
f2 omg
f1 omg
res omg

可以看到上面的compose函数接收了一个函数数组,函数里面reduce的部分有点绕,我们逐步讲解一下,首先,compose函数需要返回一个reduce函数处理过的值,reduce函数接收一个函数作为参数,这个函数的第一个参数a就相当于上面累加例子里的total,b就相当于下一个要执行的函数。到这里其实就结束了,但是我们将来还需要给函数传递参数,比如传入了一个omg字符串,那么我们希望compose函数返回值也是一个函数,我们才能在调用的时候再传递参数。所以我们在里面再套一层函数来接收参数o。

上面的compose最终的目的是实现了一个像洋葱的函数调用形式,一层包着一层 f1(f2(f3("omg")))

柯里化:把接收多个参数的函数变成接收一个参数的函数,并且返回接收余下参数而且返回结果的新函数

举个例子说明一下柯里化后的函数和之前的有什么不同

// curry之前
function add(x,y){
    return x+y
}
add(1,2)

// curry之后
function newAdd(x){
    return function(y){
        return x+y
    }
}
let aa = newAdd(1)(2)
console.log(aa)

可以看到函数的柯里化就是利用闭包的特性,记住参数,然后返回一个函数,函数的返回值是最终的结果,经过柯里化的函数我们的调用会更加灵活

那么有小伙伴问了,这个函数究竟灵活在哪里了呀?

我感觉主要是柯里化提高了函数的适用性,我们可以想用什么功能就传递什么参数,根据传入参数的数量实现函数的随取随用。增加了代码的复用性。

 

更多函数式编程知识参见:https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/ch1.html#%E4%BB%8B%E7%BB%8D

 

posted @ 2020-07-29 21:12  熊猫程序员  阅读(458)  评论(0编辑  收藏  举报