博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript中的pipe()和compose()快速介绍
阅读量:2527 次
发布时间:2019-05-11

本文共 5256 字,大约阅读时间需要 17 分钟。

Functional programming’s been quite the eye-opening journey for me. This post, and posts like it, are an attempt to share my insights and perspectives as I trek new functional programming lands.

对我而言,函数式编程是一个令人大开眼界的旅程。 这篇文章以及类似的文章是我在尝试新的函数式编程领域时试图分享我的见解和观点的尝试。

been my go-to FP library because of how much easier it makes functional programming in JavaScript. I highly recommend it.

成为了我的 FP库,因为它使JavaScript中的函数式编程变得更加容易。 我强烈推荐它。

(Pipe)

The concept of pipe is simple — it combines n functions. It’s a pipe flowing left-to-right, calling each function with the output of the last one.

pipe的概念很简单-它结合了n功能。 这是一条从左到右流动的管道,使用最后一个输出调用每个函数。

Let’s write a function that returns someone’s name.

让我们编写一个返回某人name的函数。

getName = (person) => person.name;getName({ name: 'Buckethead' });// 'Buckethead'

Let’s write a function that uppercases strings.

让我们写一个大写字符串的函数。

uppercase = (string) => string.toUpperCase();uppercase('Buckethead');// 'BUCKETHEAD'

So if we wanted to get and capitalize person's name, we could do this:

因此,如果我们想获得和利用person的名字,我们可以这样做:

name = getName({ name: 'Buckethead' });uppercase(name);// 'BUCKETHEAD'

That’s fine but let’s eliminate that intermediate variable name.

很好,但是让我们消除该中间变量name

uppercase(getName({ name: 'Buckethead' }));

Better, but I’m not fond of that nesting. It can get too crowded. What if we want to add a function that gets the first 6 characters of a string?

更好,但是我不喜欢这种嵌套。 太拥挤了。 如果我们想添加一个获取字符串的前6个字符的函数怎么办?

get6Characters = (string) => string.substring(0, 6);get6Characters('Buckethead');// 'Bucket'

Resulting in:

导致:

get6Characters(uppercase(getName({ name: 'Buckethead' })));// 'BUCKET';

Let’s get really crazy and add a function to reverse strings.

让我们变得疯狂起来,添加一个函数来反转字符串。

reverse = (string) =>  string    .split('')    .reverse()    .join('');reverse('Buckethead');// 'daehtekcuB'

Now we have:

现在我们有:

reverse(get6Characters(uppercase(getName({ name: 'Buckethead' }))));// 'TEKCUB'

It can get a bit…much.

它可能会有点…很多。

管救人! (Pipe to the rescue!)

Instead of jamming functions within functions or creating a bunch of intermediate variables, let’s pipe all the things!

让我们用pipe所有事情,而不是在函数中阻塞函数或创建大量中间变量。

pipe(  getName,  uppercase,  get6Characters,  reverse)({ name: 'Buckethead' });// 'TEKCUB'

Pure art. It’s like a todo list!

纯艺术。 这就像一个待办事项清单!

Let’s step through it.

让我们逐步进行。

For demo purposes, I’ll use a pipe implementation from one of ’s .

出于演示目的,我将使用的之一中的pipe实现。

pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);

I love this little one-liner.

我喜欢这个小单线。

Using rest parameters, , we can pipe n functions. Each function takes the output of the previous one and it’s all reduced ? to a single value.

使用rest参数, ,我们可以传递n函数。 每个函数取上一个函数的输出,并且全部减少了 ? 到单个值。

And you can use it just like we did above.

您可以像上面一样使用它。

pipe(  getName,  uppercase,  get6Characters,  reverse)({ name: 'Buckethead' });// 'TEKCUB'

I’ll expand pipe and add some debugger statements, and we’ll go line by line.

我将扩展pipe并添加一些调试器语句,然后逐行进行操作。

pipe = (...functions) => (value) => {  debugger;  return functions.reduce((currentValue, currentFunction) => {    debugger;    return currentFunction(currentValue);  }, value);};

Call pipe with our example and let the wonders unfold.

通过我们的示例调用pipe ,让奇迹得以展现。

Check out the local variables. functions is an array of the 4 functions, and value is { name: 'Buckethead' }.

检查局部变量。 functions是4个函数的数组, value{ name: 'Buckethead' }

Since we used rest parameters, pipe allows any number of functions to be used. It’ll just loop and call each one.

由于我们使用了rest参数,因此pipe允许使用任意数量的函数。 它只会循环并调用每个。

On the next debugger, we’re inside reduce. This is where currentValue is passed to currentFunction and returned.

在下一个调试器上,我们在reduce里面。 这是将currentValue传递给currentFunction并返回的地方。

We see the result is 'Buckethead' because currentFunction returns the .name property of any object. That will be returned in reduce, meaning it becomes the new currentValue next time. Let’s hit the next debugger and see.

我们看到的结果是'Buckethead'因为currentFunction返回任何对象的.name属性。 那将在reduce中返回,这意味着它下次将成为新的currentValue 。 让我们点击下一个调试器,看看。

Now currentValue is ‘Buckethead’ because that’s what got returned last time. currentFunction is uppercase, so 'BUCKETHEAD' will be the next currentValue.

现在, currentValue'Buckethead'因为这是上次返回的内容。 currentFunctionuppercase ,因此'BUCKETHEAD'将是下一个currentValue

The same idea, pluck ‘BUCKETHEAD’'s first 6 characters and hand them off to the next function.

同样的想法,选择'BUCKETHEAD'的前6个字符并将其交给下一个功能。

reverse(‘.aedi emaS’)

reverse('.aedi emaS')

And you’re done!

大功告成!

那compose()呢? (What about compose()?)

It’s just pipe in the other direction.

它只是另一个方向的pipe

So if you wanted the same result as our pipe above, you’d do the opposite.

因此,如果您希望获得与上述pipe相同的结果,则可以执行相反的操作。

compose(  reverse,  get6Characters,  uppercase,  getName)({ name: 'Buckethead' });

Notice how getName is last in the chain and reverse is first?

请注意, getName在链中是最后一个,而reverse是第一个?

Here’s a quick implementation of compose, again courtesy of the Magical , from .

这是compose的一个快速实现,同样来自的Magical 。

compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);

I’ll leave expanding this function with debuggers as an exercise to you. Play around with it, use it, appreciate it. And most importantly, have fun!

我将继续使用debugger扩展此功能,作为练习。 玩转它,使用它,欣赏它。 最重要的是,玩得开心!

翻译自:

转载地址:http://vjwzd.baihongyu.com/

你可能感兴趣的文章
使用sencha的cmd创建项目时提示找不到\Sencha\Cmd\repo\.sencha\codegen.json
查看>>
如何快速启动一个Java Web编程框架
查看>>
MSP430单片机存储器结构总结
查看>>
文本框过滤特殊符号
查看>>
教育行业安全无线网络解决方案
查看>>
7个杀手级的开源监测工具
查看>>
软件架构学习小结
查看>>
C语言实现UrlEncode编码/UrlDecode解码
查看>>
返回用户提交的图像工具类
查看>>
树链剖分 BZOJ3589 动态树
查看>>
挑战程序设计竞赛 P131 区间DP
查看>>
【例9.9】最长公共子序列
查看>>
NSFileManager打印目录下的文件的函数
查看>>
Selenium自动化-调用Mysql数据库
查看>>
项目一
查看>>
[转载]AAF灵便应用框架简介系列(6):休息一下,泛谈面向对象 Why OO+多层结构?...
查看>>
android EditView ime
查看>>
javascript 学习随笔7
查看>>
<P>标签小细节
查看>>
Linux 命令 - netstat
查看>>