Iteration is a method of accessing collection elements; objects that can be iterated are called iterable objects; an iterator is an object that can remember the traversal position. The iterator object starts accessing from the first element of the collection until After all elements have been accessed, the iterator can only move forward and not backward.
Lazy evaluation is often translated as "lazy calculation" or "lazy calculation", which refers to calculating the value of an expression only when it is actually needed to be executed.
The opposite of lazy evaluation is early evaluation. Early evaluation, also known as greedy evaluation or strict evaluation, is the evaluation strategy of most traditional programming languages.
The benefits of making full use of the characteristics of lazy evaluation are mainly reflected in the following two aspects:
Avoid unnecessary calculations and improve performance.
Saves space and makes infinite loop data structures possible.
Iterators in ES6 make it possible to lazily evaluate and create user-defined sequences of data. Iteration is a mechanism for traversing data. An iterator is a pointer used to traverse the elements of a data structure (called an Iterable), a pointer used to produce a sequence of values.
An iterator is an object that can be iterated. It abstracts the data container so that it behaves like an iterable object.
The iterator does not calculate the value of each item when instantiated and only generates the next value when requested. This is very useful, especially for large data sets or sequences of infinite elements.
An iterable object is a data structure that wants its elements to be publicly accessible. Many objects in JS are iterable. They may not be easy to detect, but if you examine carefully, you will find the characteristics of iteration:
new Map([iterable])
new WeakMap([iterable])
new Set([iterable])
new WeakSet([iterable])
String,Array,TypedArray,Map,Set.
Iteration protocol
A protocol is a set of interfaces and specifies how to use them.
Iterators follow the iterator protocol, and iterables follow the iterable protocol.Iterable protocol
To make an object iterable, it must implement an iterator method through Symbol.iterator, which is a factory for iterators .
Using TypeScript, the iterable protocol looks like this:
interface Iterable { [Symbol.iterator]() : Iterator; }
Symbol.iterator]() is a parameterless function. Calling it on an iterable object means we can access the iterable object through this, which can be a regular function or a generator function.
Iterator protocolThe iterator protocol defines a standard way to generate a sequence of values.
In order for an object to become an iterator, it must implement the next() method. Iterators can implement the return() method, which we will discuss later in this article.
Using TypeScript, the iterator protocol is as follows:
interface Iterator { next() : IteratorResult; return?(value?: any): IteratorResult; }
IteratorResult is defined as follows:
interface IteratorResult { value?: any; done: boolean; }
Composition
Example
We start with a very basic iterator, the createRangeIterator iterator.
We manually call it.next() to get the next IteratorResult. The last call returns {done: true}, which means the iterator is now used and no longer produces any values.
function createRangeIterator(from, to) { let i = from; return { next() { if (i <= to) { return { value: i++, done: false }; } else { return { done: true }; } } } } const it = createRangeIterator(1, 3); console.log(it.next()); console.log(it.next()); console.log(it.next()); console.log(it.next());
Earlier in this article, I have mentioned that certain statements in JS require a Iterable object. Therefore, our previous example will not work when used with a for...of loop.
But it is very easy to create objects that conform to the iterator and iterable protocols.
function createRangeIterator (from, to) { let i = from return { [Symbol.iterator] () { return this }, next() { if (i <= to) { return { value: i++, done: false } } else { return { done: true } } } } } const it = createRangeIterator(1, 3) for (const i of it) { console.log(i) }
迭代器可以表示无限制大小的序列,因为它们仅在需要时才计算值。
注意不要在无限迭代器上使用扩展运算符(...),JS 将尝试消费迭代器,由于迭代器是无限的,因此它将永远不会结束。 所以你的应用程序将崩溃,因为内存已被耗尽
同样,for ... of 循环也是一样的情况,所以要确保能退出循环:
function createEvenNumbersIterator () { let value = 0 return { [Symbol.iterator] () { return this }, next () { value += 2 return { value, done: false} } } } const it = createEvenNumbersIterator() const [a, b, c] = it console.log({a, b, c}) const [x, y, z] = it console.log({ x, y, z }) for (const even of it) { console.log(even) if (even > 20) { break } }
关闭迭代器
前面我们提到过,迭代器可以有选择地使用return()方法。 当迭代器直到最后都没有迭代时使用此方法,并让迭代器进行清理。
for ... of循环可以通过以下方式更早地终止迭代:
break
continue
throw
return
function createCloseableIterator () { let idx = 0 const data = ['a', 'b', 'c', 'd', 'e'] function cleanup() { console.log('Performing cleanup') } return { [Symbol.iterator]() { return this }, next () { if (idx <= data.length - 1) { return { value: data[idx++], done: false } } else { cleanup() return { done: true } } }, return () { cleanup() return { done: true } } } } const it = createCloseableIterator() for (const value of it) { console.log(value) if (value === 'c') { break } } console.log('\n----------\n') const _it = createCloseableIterator(); for (const value of _it) { console.log(value); }
如果知道迭代器已经结束,则手动调用cleanup()函数。
如果突然完成,则return()起作用并为我们进行清理。
【推荐学习:javascript高级教程】
The above is the detailed content of Do you know iterable objects and iterators in JavaScript?. For more information, please follow other related articles on the PHP Chinese website!