Generator function
A generator function is a function keyword followed by an asterisk (*).
function* generator() {
yield 1
yield 2
yield 3
}
Copy the code
Calling a generator function returns an iterator.
const iterator = generator()
iterator.next() // {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: false}
iterator.next() // {value: undefined, done: true}
Copy the code
An iterator is an object with the next method deployed, and each call returns an object containing value and done properties: value indicates the current value of the loop, and done indicates the end of the loop.
For – loops
for.. The of loop is used to iterate over iterable. The syntax is as follows:
for (variable of iterable) {
// statements
}
Copy the code
An iterable is an object that deploys the [symbol.iteraor] property, which is a method. This method is called to get iterators, so [symbol. iteraor] is also called an iterator generator.
const arr = ['a'.'b'.'c']
// (1) use a for-of loop
for (const element of arr) {
console.log(element)
}
// (2) manual loop
let iterator = arr[Symbol.iterator]()
while (true) {
let result = iterator.next()
if (result.done) break
console.log(result.value)
}
Copy the code
The for-of loop at (1) has internal execution logic as reflected in the code at (2). The final output is a -> B -> C.
For-of and generator functions
What you may not know is that the result of calling a generator function can also be iterated through a for-of loop.
Again, take generator() above:
for (const element of generator()) {
console.log(element)
}
// 1 -> 2 -> 3
Copy the code
Sure enough. But I don’t know if you have any questions, I do.
generator()
Is not the result of an iterator, why can also befor-of
Call? murphyfor-of
Not only iterable, but iterator directly, right?
Let’s try it.
for (const element of arr[Symbol.iterator]()) {
console.log(element)
}
// a -> b -> c
Copy the code
Arr [symbol.iterator]() returns an iterator that can indeed be traversed by for-of. Does that mean for-of can iterate over an iterator?
For-of can only iterate over an iterable
Look at the structure of arr[symbol.iterator]().
- support
next
The method specification is an iterator object. - And it inherits one on the prototype chain
[Symbol.iterator]
Attribute… Ah, it turns out to be an iterable.
Array arr[symbol.iterator]() returns an iterator and an iterable. This is a bit of a problem, because the [symbol. iterator] property is probably still in play here (in for-of syntax).
To fully prove this, let’s use an iterable modified from a common object:
let range = {}
range[Symbol.iterator] = function() {
return {
current: 1.last: 3,
next() {
if (this.current <= this.last) {
return { done: false.value: this.current++ }
} else {
return { done: true }
}
}
}
}
Copy the code
Let’s iterate through it with for-of:
for (let item of range) { console.log(item) } // 1 -> 2 -> 3
Copy the code
OK, no problem. The key step is to iterate over the results of range[symbol.iterator]().
for (let item of range[Symbol.iterator]()) { console.log(item) }
// TypeError: range[Symbol.iterator] is not a function or its return value is not iterable
Copy the code
An error! Range [symbol. iterator] must return an iterable.
Arr [symbol.iterator]() is iterable not because it is an iterator but because it is an iterable.
If we take it a step further, we find another interesting point:
let iterator = arr[Symbol.iterator]()
iterator[Symbol.iterator]() === iterator // true
Copy the code
Arr [symbol.iterator]() is an iterable. We call it [symbol.iterator] and find that the result is equal to itself! This is why the previous section gave us the illusion that for-of can also iterate over iterators.
The return value of a generator function is also an iterable
To return to the previous example of a generator function:
function* generator() {
yield 1
yield 2
yield 3
}
for (const element of generator()) {
console.log(element)
}
// 1 -> 2 -> 3
Copy the code
The return result of generator() is an iterator, but this object can be loiterable for absolutely because it is also iterable!
Let’s verify:
Sure enough. The same:
let iterator = generator()
iterator[Symbol.iterator]() === iterator // true
Copy the code
Ahh, iterators that are also iterables are called [symbol. iterator] and the result is equal to itself (touch your forehead again) — that’s why we have the illusion of for-of traversing iterators!
Create iterables using generator functions
For an interesting use case, let’s change the upper range object:
const range = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3; }}for (let value of range) {
console.log(value)
}
// 1 -> 2 -> 3
Copy the code
The “return value of a generator function is an iterator” feature is used.
conclusion
- The result returned by calling a generator function is an iterator object
next
Methods). At the same time, - This iterator is also an iterable. That’s why
generator()
The results can befor-of
Traversal reason!
Refer to the link
- 2 ality.com/2017/12/for…
- Developer.mozilla.org/en-US/docs/…
(End of text)
Advertising time (long term)
I have a good friend who owns a cattery, and I’m here to promote it for her. Now the cattery is full of Muppets. If you are also a cat lover and have the need, scan her FREE fish QR code. It doesn’t matter if you don’t buy it. You can just look at it.
(after)