首页 > 编程语言 >JavaScript中的Pipe

JavaScript中的Pipe

时间:2022-11-04 19:34:54浏览次数:61  
标签:pipe const JavaScript reduce Pipe prototype

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

标签:pipe,const,JavaScript,reduce,Pipe,prototype
From: https://www.cnblogs.com/sexintercourse/p/16858886.html

相关文章

  • javascript - 练习题:自定义typeof / 数组去重
    自定义typeof函数为啥要自定义typeof,因为 引用值 会被typeof 输出为object。 换句话说:typeof 不能区分 引用值(数组、对象和包装类)的具体类型;typeof 本身是可......
  • pipeline 流程
    Pipeline提交、测试、部署流程一、提交阶段:1.更新代码2.构建3.单元测试4.质量扫描node{gitlabCommitStatus(builds:["CommitBuild"]){stage('CodePUll')......
  • 原生javascript清空table表格
    本文主要分享一下原生javascript清空table表格的方法,仅供参考:lettable=document.getElementById("tableId");varlen=table.childNodes.length;for(leti=len-......
  • VideoPipe可视化视频结构化框架新增功能详解(2022-11-4)
    VideoPipe从国庆节上线源代码到现在经历过了一个月时间,期间吸引了若干小伙伴的参与,现将本阶段新增内容总结如下,有兴趣的朋友可以加微信拉群交流。项目地址:https://github.......
  • 前端100题」包含算法、Vue、Reac、Javascript、浏览器等真题和答案
    目录(https://github.com/Advanced-Frontend/Daily-Interview-Question)第1题:写React/Vue项目时为什么要在列表组件中写key,其作用是什么?.6第2题:['1','2','3'......
  • 常用的前端JavaScript方法封装
    1、输入一个值,返回其数据类型**functiontype(para){returnObject.prototype.toString.call(para)}2、数组去重functionunique1(arr){return[...newS......
  • Jenkins Pipeline 多分支流水线 Input length = 1
    Jenkins多分支流水线构建过程中报错。[Pipeline]//node[Pipeline]EndofPipelinejava.nio.charset.MalformedInputException:Inputlength=1 atjava.base/ja......
  • JavaScript异或运算
    相关性质任何数和自己做异或运算,结果为0,即a⊕a=0a⊕a=0。任何数和0做异或运算,结果还是自己,即a⊕0=⊕a⊕0=⊕。异或运算中,满足交换律和结合律,也就是a⊕b⊕a=b⊕a⊕......
  • javascript Swap two nodes调换两个元素的位置
    SwaptwonodesThefunctionbelowswapstwogivennodes,nodeAandnodeB:constswap=function(nodeA,nodeB){constparentA=nodeA.parentNode;c......
  • 如何判断Javascript函数是否是Async函数
     zhangfisher发布于 2021-04-13判断Javascript函数是否是Async函数有好几种方法:调用Object.prototype.toString.call(asyncfunction(){}),如果返回[objectAsy......