Lazy evaluation, every functional programmer’s wet dream. Soon enough, we will look at generators. But first, let's get a grasp of what iterators and iterables are because to me, they’re a prerequisite for generators.
懒惰的评估,每个函数式程序员的梦想。 很快,我们将研究发电机。 但是首先,让我们了解什么是迭代器和可迭代对象,因为对我而言,它们是生成器的先决条件。
(Lazy evaluation)
Lazy evaluation means to delay the evaluation of an expression until it’s needed. Lazy evaluation is sometimes referred to as call-by-need.
惰性求值意味着将对表达式的求值延迟到需要时才进行。 惰性评估有时称为按需调用 。
The opposite of lazy evaluation is an eager evaluation. It’s an evaluation strategy used in most programming languages.
懒惰评估的反面是渴望评估 。 这是大多数编程语言中使用的评估策略。
Lazy evaluation makes it possible to:
懒惰评估可以:
- define potentially infinite data structures
- increase performance by avoiding needless computations
- customize iteration behavior for data structures that want its elements accessible to the public
(Iterators)
Iterators in JavaScript (since ECMAScript 6) are what make it possible to lazy evaluate and create user-defined data sequences.
JavaScript中的迭代器 (自ECMAScript 6起 )使懒惰求值和创建用户定义的数据序列成为可能。
Iteration is a mechanism for traversing data. Iterators are pointers for traversing elements of data structure, called Iterable. A pointer for producing a sequence of values.
迭代是一种遍历数据的机制。 迭代器是遍历数据结构元素(称为Iterable)的指针。 用于产生值序列的指针。
An iterator is an object that can be iterated over. It abstracts a container of data to make it behave like an iterable object.
迭代器是可以迭代的对象。 它抽象出一个数据容器,使其表现得像一个可迭代的对象。
The iterator does not compute the value of each item when instantiated. The next value is generated only when requested. This is useful, especially for large data sets or sequences of an infinite number of elements.
迭代器在实例化时不计算每个项目的值。 仅在请求时才生成下一个值。 这非常有用,特别是对于大型数据集或无限个元素的序列。
(Iterables)
Iterables are data structures that want their elements accessible to the public.
可迭代对象是希望其元素可被公众访问的数据结构。
Many APIs accept iterables, for example:
许多API都接受可迭代,例如:
- new Map([iterable]) new Map([iterable])
- new WeakMap([iterable]) new WeakMap([iterable])
- new Set([iterable]) new Set([iterable])
- new WeakSet([iterable]) new WeakSet([iterable])
- Promise.all([iterable]) Promise.all([iterable])
- Promise.race([iterable]) Promise.race([iterable])
- Array.from([iterable]) Array.from([iterable])
There’re also statements and expressions that expect iterables, for example:
还有一些期望可迭代的语句和表达式,例如:
- for ... of (loop) for ... of (循环)
- ... (spread operator) ... (点差运算符)
- const [a, b, ..] = iterable; (destructuring assignment) const [a, b, ..] = iterable; (销毁工作)
- yield* (generator delegation) yield* (发电机委托)
There’s a number of already built-in iterables in JavaScript:String , Array , TypedArray , Map , Set.
JavaScript中已经有许多内置的可迭代对象: String , Array , TypedArray , Map , Set 。
(Iteration protocols)
Iterators and iterables conform to iteration protocols.
迭代器和可迭代对象符合迭代 协议 。
Protocol is set of interfaces and rules how to use them.
协议是一组接口,并规定了如何使用它们。
Iterators conform to the iterator protocol. Iterables conform to the iterable protocol.
迭代器符合迭代器协议 。 可迭代对象符合可迭代协议 。
(The iterable protocol)
Iterable protocol allows JavaScript objects to define or customize their iteration behavior.
可迭代协议允许JavaScript对象定义或自定义其迭代行为。
For an object to become iterable, it must implement an iterator method accessible through Symbol.iterator . This method is a factory for iterators.
为了使对象变得可迭代,它必须实现可通过Symbol.iterator访问的迭代器方法。 此方法是迭代器的工厂。
Using TypeScript the iterable protocol looks as follows:
使用TypeScript,可迭代协议如下所示:
interface Iterable {
[Symbol.iterator]() : Iterator;
}
[Symbol.iterator]() is a zero-argument function. It is invoked on the iterable object, which means you can access the iterable through this . It can be either a regular function or a generator function.
[Symbol.iterator]()是零参数函数。 在iterable对象上调用它,这意味着您可以通过this来访问iterable。 它可以是常规函数或生成器函数。
(The iterator protocol)
Iterator protocol defines a standard way to produce a sequence of values.
迭代器协议定义了产生值序列的标准方法。
For an object to become an iterator, it must implement a next() method. Optionally the iterator can implement a return() method, we will discuss this later in this article.
为了使对象成为迭代器,它必须实现next()方法。 可选地,迭代器可以实现return()方法,我们将在本文后面进行讨论。
Using TypeScript the iteration protocol looks as follows:
使用TypeScript,迭代协议如下所示:
interface Iterator {
next() : IteratorResult;
return?(value?: any): IteratorResult;
}
Where IteratorResult is:
其中IteratorResult为:
interface IteratorResult {
value?: any;
done: boolean;
}
- done informs the consumer if the iterator has been consumed, false means there are still values to be produced, true means the iterator has reached its end done告知消费者如果迭代器已被消耗, false手段仍有值待产, true手段迭代器已经到达其终点
- value can be any JavaScript value, it’s the value exposed to the consumer value可以是任何JavaScript值,它是暴露给使用者的值
When done is true value can be omitted.
当done为true时,可以省略value 。
(Put together)
To visualize the connection between iterable and iterator see the following image.
要可视化iterable和iterator之间的连接,请参见下图。
The connection between iterable and iterator 可迭代与迭代器之间的联系
(⌨️ Showtime)
Alright, enough theory. Let’s work through some examples. We will start with some basic examples and little by little add what we have learned so far to make things more interesting.
好了,足够的理论。 让我们来看一些例子。 我们将从一些基本示例开始,并逐步添加到目前为止所学的知识,以使事情变得更加有趣。
(Range iterator)
Let’s begin with a very basic iterator, the createRangeIterator iterator.
让我们从一个非常基本的迭代器开始,即createRangeIterator迭代器。
We’re manually calling it.next() to get the next IteratorResult. Last call returns { done: true } which means the iterator is now consumed and will not produce any more values.
我们正在手动调用it.next()以获得下一个IteratorResult 。 上次调用返回{ done: true } ,这意味着迭代器现在已消耗,将不再产生任何值。
演示地址
Simple iterator 简单的迭代器
(Iterable range iterator)
Earlier in this article, I have mentioned that some statements and expressions in JavaScript expect iterables. Because of this, our previous example will not work when used, for instance, with for ... of loop.
在本文的前面,我已经提到JavaScript中的某些语句和表达式期望可迭代。 因此,我们前面的示例在与for ... of循环一起使用时将不起作用。
But it’s easy enough to create an object that conforms to both iterator and iterable protocols.
但是创建符合迭代器和可迭代协议的对象非常容易。
To visualize this see the following image.
要使其可视化,请参见下图。
An object that is both iterable and iterator
既可迭代又可迭代的对象
演示地址
Iterable iterator
可迭代的迭代器
(Infinite sequence iterator)
Iterators can express sequences of unlimited size because they compute the value only when you ask for it.
迭代器可以表达无限制大小的序列,因为它们仅在您需要时才计算值。
Be careful not to use spread operator (...) on infinite iterators. JavaScript will try to consume the iterator and since the iterator is infinite it will never reach its end. Instead, your app will crash because you will run out of memory.
注意不要在无限迭代器上使用扩展运算符( ... )。 JavaScript将尝试使用迭代器,并且由于迭代器是无限的,因此它将永远不会结束。 相反,您的应用程序将崩溃,因为您将耗尽内存。
Also the for ... of loop over such iterable would be endless. Make sure to exit the loop. Otherwise, you will also run out of memory.
同样for ... of循环的for ... of循环将是无止境的。 确保退出循环。 否则,您还将耗尽内存。
演示地址
Infinite iterator
无限迭代器
(Closing iterator)
Earlier we mentioned iterators can optionally have a return() method. This method is used when the iterator was not iterated over until the end and lets the iterator do a cleanup.
前面我们提到过,迭代器可以有选择地使用return()方法。 当迭代器直到最后都没有迭代时使用此方法,并让迭代器进行清理。
for ... of loops can terminate the iteration earlier by:
for ... of循环可以通过以下方式更早地终止迭代:
- break break
- continue (when you continue outer loop with label) continue (当您继续使用标签进行外循环时)
- throw throw
- return return
The following constructs close iterators that are not consumed:
以下构造关闭了不使用的迭代器:
- for ... of for ... of
- yield* yield*
- destructuring
- Array.from Array.from
- Map(), Set(), WeakMap(), WeakSet() Map(), Set(), WeakMap(), WeakSet()
- Promise.all(), Promise.race() Promise.all(), Promise.race()
Taken from https://2ality.com/2015/02/es6-iteration.html.
取自https://2ality.com/2015/02/es6-iteration.html 。
演示地址
Iterator cleanup through return()
通过return()进行迭代器清除
- If you know that the iterator has reached its end you call the cleanup() function manually. 如果您知道迭代器已经结束,则可以手动调用cleanup()函数。
- If there was an abrupt completion, the return() comes into play and does the cleanup for us. 如果突然完成,则return()起作用并为我们进行清理。
(💥 Extra)
If you have made it to this point, let’s add something extra.
如果您已经做到了这一点,让我们添加一些额外的内容。
(Combinators)
Combinators are functions that combine existing iterables to create new ones. A composition of iterables.
组合器是将现有可迭代对象组合在一起以创建新可迭代对象的函数。 可迭代的组成。
Because of this, we are able to create a lot of utility functions. How about map or filter? See the following code and give it a minute to sink in.
因此,我们能够创建许多实用程序功能。 map或filter怎么样? 请参阅下面的代码,花一分钟时间沉浸其中。
演示地址
Combinators
组合器
Yay! That was a lot of code. Soon we will look at how all this can be refactored using generators and functional programming concepts. You will be surprised how compact all of this code can get.
好极了! 那是很多代码。 很快,我们将研究如何使用生成器和函数式编程概念来重构所有这些。 您将惊讶于所有这些代码的紧凑程度。
Stay safe, stay tuned, and watch out for my upcoming articles, we still have got a lot to cover.
保持安全,保持关注,并注意我的后续文章,我们仍然有很多内容要讲。
(Resources)
- https://exploringjs.com/es6/ch_iteration.html https://exploringjs.com/es6/ch_iteration.html
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols
- https://swizec.com/blog/finally-a-practical-use-case-for-javascript-generators/ https://swizec.com/blog/finally-a-practical-use-case-for-javascript-generators/
- https://2ality.com/2015/02/es6-iteration.html https://2ality.com/2015/02/es6-iteration.html
- https://www.freecodecamp.org/news/how-and-why-you-should-use-python-generators-f6fb56650888/ https://www.freecodecamp.org/news/how-and-why-you-should-use-python-generators-f6fb56650888/
- https://vegibit.com/iterators-in-es6/#:~:text=ES6%20now%20has%20what's%20known,that%20returns%20an%20iterator%20object. https://vegibit.com/iterators-in-es6/#:~:text=ES6%20now%20has%20what%20%,那个%20返回%20an%20iterator%20object 。
- https://en.wikipedia.org/wiki/Lazy_evaluation https://zh.wikipedia.org/wiki/懒惰评估
翻译自: https://medium.com/javascript-in-plain-english/javascript-lazy-evaluation-iterables-iterators-e0770a5de96f