• JavaScript中的Pipe


    JavaScript中的Pipe

    本文会介绍Pipe在函数式编程中的基本概念,怎么用Pipe让我们的代码变得更美好,以及新的pipe操作符,Fancy的东西在后面!
    什么是Pipe?
    先用一个最简单的例子来看一下什么是pipe,现在我们有两个最简单的函数addOne和addTwo,分别对于参数加一和加二:

    const addOne = x => x + 1
    const addTwo = x => x + 2

    现在我们想让一个参数通过第一个函数之后再通过第二个函数,最直接最简单的方法是:

    addTwo(addOne(1)) // 4

    我们来写一个简单的pipe函数,它返回一个新的函数,来达到我们上面的目的:

    const pipe = (func1, func2) => x => func2(func1(x))
     
    const addThree = pipe(
      addOne,
      addTwo
    )
     
    addThree(1) // 4

    嗯,现在还看不出来什么好处,但是当我们要经过的Transform越来越多的时候,这样的好处就会越来越明显:

    const addTen = pipe(
      addOne,
      addTwo,
      addThree,
      addFour
    )

    所以我们需要一个更牛逼的pipe函数,它可以接受任意数量的参数,并从第一个开始,依次接受原始数值,输出值传递给下一个函数。等等,我们好像想到了什么,遍历一个数组,把输出值当作下一个的输入,怎么听着都和reduce很像。所以,直接用Array.prototype.reduce就可以写一个简单的pipe函数:

    const pipe = ...args => x => 
      args.reduce(
        (outputValue, currentFunction) => currentFunction(outputValue),
        x
      )
    • 为什么要用Pipe

    Pipe让我们将一些小功能随意的拼凑组合在一起,组成我们自己需要的功能。还记得React中的High Order Component(HOC)吗?越来越多的插件开始让你使用HOC,比如我经常遇到类似下面的代码:

    // 没有pipe,function hell...
    withRouter(
      withTitle('Awesome title')(
        translate('translations')(
          connect(mapStateToProps, mapDispatchToProps)(
            Container
          )
        )
      )
    )
     
    // 使用pipe
    pipe(
      connect(mapStateToProps, mapDispatchToProps),
      translate('translations'),
      withTitle('Awesome title'),
      withRouter
    )(Container)
     
    // 使用pipe组成你需要的pattern
    const withGeneralContainerProps = pipe(
      connect(mapStateToProps, mapDispatchToProps),
      translate('translations'),
      withTitle('Awesome title'),
      withRouter
    )
     
    withGeneralContainerProps(Container)
    • Pipe和Prototype

    在JavaScript中,经常有通过prototype进行的链式操作,一般来说这种代码如果在项目中看到还是挺喜闻乐见的,感觉代码还是比较干净,比如:

    [1, 2, 3, 3, 5]
      .map(i => i * 2)
      .filter(i => i !== 10)
      .reduce((acc, cur) => acc + cur)

    但同时,基于prototype的这种链式操作是很难扩展的,比如我们想在上面的代码中间加一个新的操作符uniq,去除重复值:

    // 臣妾做不到。。。因为没有Array.prototype.uniq。。。
    [1, 2, 3, 3, 5]
      .map(i => i * 2)
      .uniq()
      .filter(i => i !== 10)
      .reduce((acc, cur) => acc + cur)
     
    // 有一种办法是在之前的某个地方改变prototype, 但你真的想这么做么?
    Array.prototype.uniq = function () {
      return Array.from(new Set(this))
    }

    不过如果我们把每个小函数拆开来,使用pipe,在保持代码清晰的同时,扩展性得到了巨大的提升,比如下面的写法

    import * as R from 'ramda'
     
    R.pipe(
      R.map(i => i * 2),
      R.uniq,
      R.filter(i => i !== 10),
      R.reduce(R.add, 0)
    )([1, 2, 3, 3, 5])

    更多关于Ramda可以参考Github或文档。同时要提一下的是,这也是为什么rxjs现在全改成了用pipe,而不使用prototype的原因。

    等等,也许你并不需要Pipe?
    刚才我们所做的其实都是在用functional programming的方式去写JavaScript,更彻底更优雅的解决方式,可能是在语法上的改变。Proposal-pipeline-operator已经在JavaScript中社区提出来一段时间了,但是具体方案还有分歧,可以去看Github Issue,这里我们就不说太多了,但是就算是基础版本的方案,个人觉得也是非常大的便利,而且如果你在用Babel,今天就可以开始使用。

    按照Babel文档添加插件,proposal先用minimal就好,等你弄清楚别的可以再尝试:

    {
      "plugins": [["@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" }]]
    }

    还是上面的例子:

    import * as R from 'ramda'
     
    [1, 2, 3, 4, 5]
      |> R.map(i => i * 2)
      |> R.uniq
      |> R.filter(i => i !== 10)
      |> R.reduce(R.add, 0)
      // 是的,我们还可以写arrow function,
      |> (_ => 'done, result is ' + _)
      |> console.log

    或者是React的例子:

    Container
      |> connect(mapStateToProps, mapDispatchToProps)
      |> translate('translations')
      |> withTitle('Awesome title')
      |> withRouter

    哇塞,看的真是有点爽,JavaScript什么时候加一下Pattern match...简单说来

    a |> b // b(a)

    在Elixir,Ocaml等等的函数式语言中其实一直都有,而且社区对于怎么支持async function还有两个不同的提案,感兴趣的同学们都可以去尝试。

    虽然只是写法上的不同,但是我相信这个改变的影响还是会比较深远的,语言的不同会慢慢导致大家思考问题的方式有细微的差异,期待这个提案尽快确定下来~

    React都用Hook了,还要什么Class !

    小编是一个有着5年工作经验的前端开发工程师,关于前端编程,自己有做材料的整合,一个完整的前端编程学习路线,学习材料和工具,+我的威信收取,免费送给tanzhou-10838大家,希望你也能凭着自己的努力,成为下一个优秀的程序员。
    ————————————————
    版权声明:本文为CSDN博主「程序员一木」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/tzllxya/article/details/90702581

  • 相关阅读:
    media query 开发总结
    整屏滚动
    移动端reset样式
    中国天气网 城市代码 sql语句
    php文章tag标签的增删
    oracle的分号和斜杠/
    php 操作 oracle lob 数据2
    php 操作 oracle lob 数据
    oracle创建用户
    php进度条
  • 原文地址:https://www.cnblogs.com/sexintercourse/p/16858886.html
Copyright © 2020-2023  润新知