zoukankan      html  css  js  c++  java
  • JavaScript 函数式编程中 compose 实现

    简介

    比如有这样的需求,要输入一个名字,这个名字有由firstName,lastName组合而成,然后把这个名字全部变成大写输出来,比如输入jack,smith我们就要打印出来,‘HELLO,JACK SMITH’ 。

    我们考虑用函数组合的方法来解决这个问题,需要两个函数greeting, toUpper

    var greeting = (firstName, lastName) => 'hello, ' + firstName + ' ' + lastName
    var 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]可以看出允许数组为空,可以看出还是非常严谨的。我写的就缺少这种严谨的异常处理。

    豌豆资源搜索网站https://55wd.com 广州vi设计公司http://www.maiqicn.com

  • 相关阅读:
    设计模式系列
    【ABAP系列】SAP ABAP 关于FUNCTION-POOL的理解
    【MM系列】SAP S/4 HANA 1511的BP角色创建及供应商数据的创建方法
    【ABAP系列】SAP ABAP 动态指针
    【HR系列】SAP HR PA信息类型的创建与增强
    【HANA系列】SAP UI5上传图片 用XSJS存储在HANA中的方法
    【HANA系列】SAP Vora(SAP HANA和Hadoop)简析
    【MM系列】SAP SAP库龄报表逻辑理解
    【HANA系列】SAP HANA XS Administration Tool登录参数设置
    【ABAP系列】SAP 一个完整的SAP的Abap例子(idoc,edi文件的相互转换)
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/13740070.html
Copyright © 2011-2022 走看看