博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript运算符_让我们尝试使用JavaScript中的函数生成器和管道运算符
阅读量:2521 次
发布时间:2019-05-11

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

javascript运算符

was named one of the !

被评为

A generator is a function that returns the next value from the sequence each time it is called.

生成器是一种函数,每次调用时都会从序列中返回下一个值。

Combining functional generators with the pipeline operator and pure functions with intention revealing names, allows to write code in a more expressive manner, without creating intermediary lists:

将函数生成器与管道运算符以及具有意图显示名称的纯函数结合使用,可以以更富表现力的方式编写代码,而无需创建中介列表:

import { sequence, filter, map, take, toList } from "./sequence";const filteredTodos =  sequence(todos)   |> filter(isPriorityTodo)   |> map(toTodoView)  |> take(10)    |> toList;

Let’s see how.

让我们看看如何。

I’ll start with a simple functional generator that gives the next integer each time is called. It starts from 0.

我将从一个简单的函数生成器开始,该函数生成器在每次调用时给出下一个整数。 从0开始。

function sequence() {  let count = 0;  return function() {    const result = count;    count += 1;    return result;  }}const nextNumber = sequence();nextNumber(); //0nextNumber(); //1nextNumber(); //2

nextNumber() is an infinite generator. nextNumber() is also a closure function.

nextNumber()是一个无限生成器。 nextNumber()也是一个关闭函数。

有限发电机 (Finite generator)

Generators can be finite. Check the next example where sequence() creates a generator that returns consecutive numbers from a specific interval. At the end of the sequence it returns undefined:

生成器可以是有限的。 检查下一个示例,其中sequence()创建一个生成器,该生成器从特定间隔返回连续的数字。 在序列末尾,它返回undefined

function sequence(from, to){ let count = from; return function(){   if(count< to){      const result = count;      count += 1;      return result;    }  }}const nextNumber = sequence(10, 15);nextNumber(); //10nextNumber(); //12nextNumber(); //13nextNumber(); //14nextNumber(); //undefined

toList() (toList())

When working with generators, we may want to create a list with all the values from the sequence. For this situation, we need a new function toList() that takes a generator and returns all the values from the sequence as an array. The sequence should be finite.

当使用生成器时,我们可能想创建一个包含序列中所有值的列表。 对于这种情况,我们需要一个新函数toList() ,它使用一个生成器并将序列中的所有值作为数组返回。 顺序应该是有限的。

function toList(sequence) {  const arr = [];  let value = sequence();  while (value !== undefined) {    arr.push(value);    value = sequence();  }  return arr;}

Let’s use it with the previous generator.

让我们将其与上一个生成器一起使用。

const numbers = toList(sequence(10, 15));//[10,11,12,13,14]

管道运营商 (The pipeline operator)

A pipeline is a series of data transformations where the output of one transformation is the input of the next one.

管道是一系列数据转换,其中一个转换的输出是下一个转换的输入。

The pipeline operator |> enables us to write data transformations in a more expressive way. The pipeline operator provides syntactic sugar over function calls with a single argument. Consider the next code:

管道运算符|>使我们能够以更具表现力的方式编写数据转换。 管道运算符通过单个参数为函数调用提供语法糖。 考虑下一个代码:

const shortText = shortenText(capitalize("this is a long text"));function capitalize(text) {  return text.charAt(0).toUpperCase() + text.slice(1);}function shortenText(text) {  return text.substring(0, 8).trim();}

With the pipeline operator the transformation can be written like this:

使用管道运算符,转换可以这样编写:

const shortText = "this is a long text"   |> capitalize   |> shortenText;  //This is

At this moment the pipeline operator is experimental. You can try it using Babel:

目前,管道运营商正在试验中。 您可以使用Babel尝试一下:

  • in package.json file add the babel pipeline plugin:

    package.json文件中,添加babel管道插件:

{  "dependencies": {    "@babel/plugin-syntax-pipeline-operator": "7.2.0"  }}
  • in the .babelrc configuration file add:

    .babelrc配置文件中添加:

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

发电机超过收藏 (Generators over collections)

In I had an example of processing a list of todos . Here is the code:

在我有一个处理todos列表的示例。 这是代码:

function isPriorityTodo(task) {  return task.type === "RE" && !task.completed;}function toTodoView(task) {  return Object.freeze({ id: task.id, desc: task.desc });}const filteredTodos = todos.filter(isPriorityTodo).map(toTodoView);

In this example, the todos list goes through two transformations. First a filtered list is created, then a second list with the mapped values is created.

在此示例中, todos列表经历了两次转换。 首先创建一个过滤列表,然后创建第二个具有映射值的列表。

With generators, we can do the two transformations and create only one list. For this, we need a generator sequence() that gives the next value from a collection.

使用生成器,我们可以执行两个转换并仅创建一个列表。 为此,我们需要一个生成器sequence() ,它提供集合中的下一个值。

function sequence(list) {  let index = 0;  return function() {    if (index < list.length) {      const result = list[index];      index += 1;      return result;    }  };}

filter()和map() (filter() and map())

Next, we need two decorators filter() and map(), that work with functional generators.

接下来,我们需要两个装饰filter()map() ,它们与函数生成器一起工作。

filter() takes a generator and creates a new generator that only returns the values from the sequence that satisfies the predicate function.

filter()一个生成器并创建一个新的生成器,该生成器仅返回满足谓词功能的序列中的值。

map() takes a generator and creates a new generator that returns the mapped value.

map()一个生成器并创建一个新的生成器,该生成器返回映射的值。

Here are the implementations:

这里是实现:

function filter(predicate) {  return function(sequence) {    return function filteredSequence() {      const value = sequence();      if (value !== undefined) {        if (predicate(value)) {          return value;        } else {          return filteredSequence();        }      }    };  };}function map(mapping) {  return function(sequence) {    return function() {      const value = sequence();      if (value !== undefined) {        return mapping(value);      }    };  };}

I would like to use these decorators with the pipeline operator. So, instead of creating filter(sequence, predicate){ } with two parameters, I created a curried version of it, that will be used like this: filter(predicate)(sequence). This way, it works nicely with the pipeline operator.

我想将这些装饰器与管道运算符一起使用。 因此,我没有使用两个参数来创建filter(sequence, predicate){ } ,而是创建了它的咖喱版本,将其使用如下: filter(predicate)(sequence) 。 这样,它可以与管道运算符很好地协同工作。

Now that we have the toolbox, made of sequence, filter, map and toList functions, for working with generators over collections, we can put all of them in a module ("./sequence"). See below for how to rewrite the previous code using this toolbox and the pipeline operator:

现在,我们有了由sequencefiltermaptoList函数组成的工具箱,用于与集合上的生成器一起使用,我们可以将所有工具箱都放在一个模块中( "./sequence" )。 有关如何使用此工具箱和管道运算符重写以前的代码的信息,请参见下文:

import { sequence, filter, map, take, toList } from "./sequence";const filteredTodos =  sequence(todos)   |> filter(isPriorityTodo)   |> map(toTodoView)   |> toList;

Here is a measuring the difference between using array methods and using functional generators. It seems that the approach with functional generators is 15–20% slower.

这是一项用于衡量使用数组方法和使用函数生成器之间的差异。 似乎使用函数发生器的方法要慢15–20%。

减少() (reduce())

Let’s take another example that computes the price of fruits from a shopping list.

让我们再举一个例子,该例子从购物清单中计算水果的价格。

function addPrice(totalPrice, line){   return totalPrice + (line.units * line.price);}function areFruits(line){   return line.type === "FRT";}let fruitsPrice = shoppingList.filter(areFruits).reduce(addPrice,0);

As you can see, it requires us to create a filtered list first and then it computes the total on that list. Let’s rewrite the computation with functional generators and avoid the creation of the filtered list.

如您所见,它要求我们首先创建一个过滤列表,然后再计算该列表上的总数。 让我们用函数生成器重写计算,避免创建过滤列表。

We need a new function in the toolbox: reduce(). It takes a generator and reduces the sequence to a single value.

我们需要在工具箱中添加一个新函数: reduce() 。 它需要一个生成器并将序列减少为单个值。

function reduce(accumulator, startValue) {  return function(sequence) {    let result = startValue;    let value = sequence();    while (value !== undefined) {      result = accumulator(result, value);      value = sequence();    }    return result;  };}

reduce() has immediate execution.

reduce()立即执行。

Here is the code rewritten with generators:

这是用生成器重写的代码:

import { sequence, filter, reduce } from "./sequence";const fruitsPrice = sequence(shoppingList)   |> filter(areFruits)   |> reduce(addPrice, 0);

采取() (take())

Another common scenario is to take only the first n elements from a sequence. For this case we need a new decorator take(), that receives a generator and creates a new generator that returns only the first n elements from the sequence.

另一种常见情况是仅从序列中获取前n元素。 对于这种情况,我们需要一个新的装饰器take() ,它接收一个生成器并创建一个新生成器,该生成器仅返回序列中的前n元素。

function take(n) {  return function(sequence) {    let count = 0;    return function() {      if (count < n) {        count += 1;        return sequence();      }    };  };}

Again, this is the curried version of take() that should be called like this: take(n)(sequence).

同样,这是take()的咖喱版本,应这样调用: take(n)(sequence)

Here is how you can use take() on an infinite sequence of numbers:

这是如何在无限的数字序列上使用take()

import { sequence, toList, filter, take } from "./sequence";function isEven(n) {  return n % 2 === 0;}const first3EvenNumbers = sequence()    |> filter(isEven)   |> take(3)   |> toList;  //[0, 2, 4]

I remade the previous and use take() to process only the first 100 items. It turns out that the version with functional generators is a lot faster (like 170 times faster).

我重新进行了之前的并使用take()仅处理前100个项目。 事实证明,带有函数发生器的版本要快得多(例如快170倍)。

let filteredTodos = todos .filter(isPriorityTodo) .slice(0, 100) .map(toTodoView);//320 ops/seclet filteredTodos =const filteredTodos =  sequence(todos)   |> filter(isPriorityTodo)   |> map(toTodoView)  |> take(100)  |> toList;//54000 ops/sec

定制发电机 (Custom generators)

We can create any custom generator and use it with the toolbox and the pipeline operator. Let’s create the Fibonacci custom generator:

我们可以创建任何自定义生成器,并将其与工具箱和管道运算符一起使用。 让我们创建斐波那契自定义生成器:

function fibonacciSequence() {  let a = 0;  let b = 1;  return function() {    const aResult = a;    a = b;    b = aResult + b;    return aResult;  };}const fibonacci = fibonacciSequence();fibonacci();fibonacci();fibonacci();fibonacci();fibonacci();const firstNumbers = fibonacciSequence()    |> take(10)   |> toList;  //[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

结论 (Conclusion)

The pipeline operator makes data transformation more expressive.

管道运算符使数据转换更具表现力。

Functional generators can be created over finite or infinite sequences of values.

可以在有限或无限的值序列上创建函数生成器。

With generators we can do list processing without creating intermediary lists at each step.

使用生成器,我们可以执行列表处理,而无需在每个步骤中创建中间列表。

You can check all the samples on .

您可以在上检查所有样本。

was named one of the !

被称为

For more on applying functional programming techniques in React take a look at .

有关在React中应用函数式编程技术的更多信息,请查看

Learn functional React, in a project-based way, with .

通过 ,以基于项目的方式学习功能性React

翻译自:

javascript运算符

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

你可能感兴趣的文章
苹果 OS X制作u盘启动盘
查看>>
Jquery便利对象
查看>>
MVC: Connection String
查看>>
idea常用设置汇总
查看>>
Node.SelectNodes
查看>>
Lambda表达式语法进一步巩固
查看>>
Vue基础安装(精华)
查看>>
Git 提交修改内容和查看被修改的内容
查看>>
PAT - 1008. 数组元素循环右移问题 (20)
查看>>
请求出现 Nginx 413 Request Entity Too Large错误的解决方法
查看>>
配置php_memcache访问网站的步骤
查看>>
hibernate的id生成策略
查看>>
树莓派3B+学习笔记:5、安装vim
查看>>
[Spfa][bfs] Jzoj P5781 秘密通道
查看>>
企业帐号进行IPA的打包、分发、下载安装的详细流程(转载)
查看>>
《项目架构那点儿事》——快速构建Junit用例
查看>>
{"errmsg":"invalid weapp pagepath hint: [IunP8a07243949]","errcode":40165}微信的坑
查看>>
DB2V9.5数据库使用pdf
查看>>
Java Bigdecimal使用
查看>>
SQL注入之绕过WAF和Filter
查看>>