JavaScript中的pipe()和compose()快速介绍

本文介绍了JavaScript中的函数组合概念,特别是Ramda库中的pipe()和compose()。pipe()从左到右串联函数,compose()则从右到左。通过示例展示了如何使用这两个工具来简化代码,避免嵌套和中间变量,提升代码可读性。
摘要由CSDN通过智能技术生成

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.

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

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

Ramda成为了我的首选 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 Eric Elliott’s functional programming articles.

出于演示目的,我将使用Eric Elliott功能性编程文章之一中的pipe实现。

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

I love this little one-liner.

我喜欢这个小单线。

Using rest parameters, see my article on that, 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 Eric Elliott, from the same article.

这是compose的一个快速实现,同样来自同一篇文章的Magical Eric Elliott

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扩展此功能,作为练习。 玩转它,使用它,欣赏它。 最重要的是,玩得开心!

翻译自: https://www.freecodecamp.org/news/pipe-and-compose-in-javascript-5b04004ac937/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值