今天小编跟大家讲解下有关JavaScript 函数式编程中 compose 实现 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了有关JavaScript 函数式编程中 compose 实现 的相关资料,希望小伙伴们看了有所帮助。
简介比如有这样的需求 要输入一个名字 这个名字有由firstName,lastName组合而成 然后把这个名字全部变成大写输出来 比如输入jack smith我们就要打印出来 ‘HELLO JACK SMITH’。
我们考虑用函数组合的方法来解决这个问题 需要两个函数greeting,toUpper
var greeting = (firstName, lastName) => 'hello, ' + firstName + ' ' + lastNamevar toUpper = str => str.toUpperCase()var fn = compose(toUpper, greeting)console.log(fn('jack', 'smith'))// ‘HELLO JACK SMITH’这就是compose大致的使用 总结下来要注意的有以下几点
compose的参数是函数 返回的也是一个函数因为除了第一个函数的接受参数 其他函数的接受参数都是上一个函数的返回值 所以初始函数的参数是多元的 而其他函数的接受值是一元的compsoe函数可以接受任意的参数 所有的参数都是函数 且执行方向是自右向左的 初始函数一定放到参数的最右面知道这三点后 就很容易的分析出上个例子的执行过程了 执行fn('jack', 'smith')的时候 初始函数为greeting 执行结果作为参数传递给toUpper 再执行toUpper 得出最后的结果 compose的好处我简单提一下 如果还想再加一个处理函数 不需要修改fn 只需要在执行一个compose 比如我们再想加一个trim 只需要这样做
var trim = str => str.trim()var newFn = compose(trim, fn)console.log(newFn('jack', 'smith'))就可以了 可以看出不论维护和扩展都十分的方便。
实现例子分析完了 本着究其根本的原则 还是要探究与一下compose到底是如何实现的 首先解释介绍一下我是如何实现的 然后再探求一下 JavaScript函数式编程的两大类库 lodash.js和ramda.js是如何实现的 其中ramda.js实现的过程非常函数式。
我的实现我的思路是 既然函数像多米诺骨牌式的执行 我首先就想到了递归 下面就一步一步的实现这个compose 首先 compose返回一个函数,为了记录递归的执行情况 还要记录参数的长度len,还要给返回的函数添加一个名字f1。
var compose = function(...args) { var len = args.length return function f1() { }}函数体里面要做的事情就是不断的执行args中的函数 将上一个函数的执行结果作为下一个执行函数的输入参数,需要一个游标count来记录args函数列表的执行情况。
var compose = function(...args) { var len = args.length var count = len - 1 var result return function f1(...args1) { result = args[count].apply(this, args1) count-- return f1.call(null, result) }}这个就是思路 当然这样是不行的 没有退出条件 递归的退出条件就是最后一个函数执行完的时候 也就是count为0的时候 这时候 有一点要注意 递归退出的时候 count游标一定要回归初始状态 最后补充一下代码
var compose = function(...args) { var len = args.length var count = len - 1 var result return function f1(...args1) { result = args[count].apply(this, args1) if (count <= 0) { count = len - 1 return result } else { count-- return f1.call(null, result) } } }这样就实现了这个compose函数。后来我发现递归这个完全可以使用迭代来实现 使用while函数看起来更容易明白 其实lodash.js就是这么实现的。
lodash实现lodash的思路同上 不过是用迭代实现的 我就把它的源代码贴过来看一下
var flow = function(funcs) { var length = funcs.length var index = length while (index--) { if (typeof funcs[index] !== 'function') { throw new TypeError('Expected a function'); } } return function(...args) { var index = 0 var result = length ? funcs[index].apply(this, args) : args[0] while (++index < length) { result = funcs[index].call(this, result) } return result }}var flowRight = function(funcs) { return flow(funcs.reverse())}可以看出 lodash的本来实现是从左到右的 但也提供了从右到左的flowRight 还多了一层函数的校验 而且接收的是数组 不是参数序列,而且从这行var result = length ? funcs[index].apply(this, args) : args[0]可以看出允许数组为空 可以看出还是非常严谨的。我写的就缺少这种严谨的异常处理。
来源:爱蒂网