Note: This is a compilation of notes from Understanding ECMAScript 6 on Github, which also includes the code samples. You can read the book when you have time. Although English, but easy to understand, highly recommended.
I was asked in the interview why there is a Generator, but I was not confused. You want to know? Scroll down.
The original link
This section describes the origin and basic concepts of generator. For those who are familiar with or want to learn more about advanced uses of generator, see how to make an error in generator.
The problem of circulation
To traverse an array in ES5, you need to:
const colors = ["red"."green"."blue"];
for (var i = 0, len = colors.length; i < len; i++) {
console.log(colors[i]);
}
Copy the code
As can be seen:
- It has to track the subscript position,
- Also determine when the loop stops.
The logic of this code is simple, but the writing is complicated and boring. And it’s very common, so it’s very easy to get bugs because of hand shaking. To simplify writing and reduce error rates, ES6 introduces some new syntax, one of which is iterator.
What is the iterator
Iterator is also an object, but it has an interface designed for iteration. It has a next method that returns an object (result) containing both value and done attributes. The former is the value of the iteration, while the latter is a flag indicating whether the iteration is complete — a Boolean value: true indicates that the iteration is complete, false indicates that it is not. Iterator has a pointer inside to the iterator position, and each time next is called, the pointer is automatically moved and the corresponding result is returned.
Here is a custom iterator:
function createIterator(items) {
var i = 0;
return {
next: function () {
var done = (i >= items.length);
var value = !done ? items[i++] : undefined; return {
done: done, value: value }; }}; } var iterator = createIterator([1, 2, 3]); console.log(iterator.next()); //"{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"// All subsequent calls return the same result console.log(iterator.next()); //"{ value: undefined, done: true }"
Copy the code
As you can see, we just need to execute next over and over again, without manually tracking the location of the iteration. It’s a little bit simpler than the opening loop.
Note: The value returned by the last iteration is not the value in the collection (items in the previous example), but the value returned by undedined or the function. See here to see how the return value relates to result
What is the generator
This is a bit simpler than the for loop, but writing an iterator by hand is too cumbersome, so ES6 provides a Generator for creating iterators. That is, generator is a function that returns an iterator.
The syntax is as follows:
function* createIterator() { yield 1; yield 2; yield 3; } // generators can be called just like normal functions, except that they return an iteratorletiterator = createIterator(); console.log(iterator.next().value); // 1 console.log(iterator.next().value); // 2 console.log(iterator.next().value); / / 3Copy the code
* indicates that this is a generator, yield returns value when calling next.
The generator in the method can be abbreviated:
let o = {
createIterator: function* (items) {
for (leti = 0; i < items.length; i++) { yield items[i]; }}}; / / is equivalent tolet o = {
*createIterator(items) {
for (leti = 0; i < items.length; i++) { yield items[i]; }}};Copy the code
As you can see, there are three ways to create a generator function
-
Function declaration
function* createIterator() {... }Copy the code
-
Functional expression
const createIterator = function* () {... }Copy the code
-
Object shorthand
leto = { *createIterator(items) { ... }};Copy the code
You can add * between the function keyword and the function name, but the key and the function name can be omitted in different scenarios
[function] * [name]() {} // * Can be close to the keyword, close to the function name, or neitherCopy the code
Note:
-
Note that yield cannot cross functions:
function* createIterator(items) { items.forEach(function(item) {// Syntax error yield item + 1; }); }Copy the code
-
Arrow functions cannot be used as generators
Iterable and for-of loops
可迭代
Closely related to iterator, there is an object called iterable. It has a symbol. iterator property whose value is a generator function.
In code, iterable looks like this:
let collection = {
items: [],
*[Symbol.iterator]() {
for (letitem of this.items) { yield item; }}};Copy the code
Collections such as sets, sets, maps, and even strings in ES6 are iterable. Iterators created by the generator are added symbol. iterator by default, so they are also iterable.
All iterable can also use for-of loops.
For – loops
Even with iterator, you can iterate simply by calling its next method. However, each call is too cumbersome to do manually, so ES6 introduces for-of loops:
const colors = ["red"."green"."blue"];
for (let color of colors) {
console.log(color);
}
Copy the code
Contrast the opening for loop:
const colors = ["red"."green"."blue"];
for (var i = 0, len = colors.length; i < len; i++) {
console.log(colors[i]);
}
Copy the code
You can see the for-of loop
- Don’t track the iteration position;
- Do not judge the cycle termination condition;
Simply declare the value of each iteration of the variable activity, which is straightforward.
Note: for-of can only be used on iterable, other objects will cause an error.
The built-in iterator
Iterator is an important part of ES6. Some built-in data types have iterator built in for easy development.
Here’s a quick look at the data types that have iterators. Simple, but not unimportant.
A collection of the iterator
There are three types of collections in ES6:
- An array of
- set
- map
The iterators below them have:
Entries (): Returns an iterator that iterates as key-value pairs; Values (): an iterator that returns the value of the set as the result of the iteration; Keys (): an iterator that returns the result of the iteration as the key in the collection;
The following uses MAP as an example:
let tracking = new Map([
['name'.'jeyvie'],
['pro'.'fd'],
['hobby'.'programming']]);for (letentry of tracking.entries()) { console.log(entry); } / / /"name"."jeyvie"] / ["pro"."fd"] / ["hobby"."programming"]
for (let key of tracking.keys()) {
console.log(key);
}
// name
// pro
// hobby
for (let value of tracking.values()) {
console.log(value);
}
// jeyvie
// fd
// programming
Copy the code
Where key and value in set are equal, both are values in set. The key of the array is its index, and the value is the value inside.
In addition, each collection has a default iterator for for-of calls. The result of its execution reflects how the collection was initialized.
Tracking:
for (letvalue of tracking) { console.log(value); } / / /"name"."jeyvie"] / ["pro"."fd"] / ["hobby"."programming"]
Copy the code
The corresponding Map instantiation is a subitem – an array of two elements.
Other sets and arrays are similar.
Note that both Chrome V65 and Node V8.0 have no values() arrays verified. Maybe it’s because it’s redundant for an array.
Iterator of strings
Iterator is a string that iterates based on a code point rather than a code unit. Compare two examples:
Example 1: Based on code Unit
var message = "A 𠮷 B";
for (leti=0; i < message.length; i++) { console.log(message[i]); } // A // (empty) // � // � // (empty) // BCopy the code
Example 2: Based on Code Point
var message = "A 𠮷 B";
for (letc of message) { console.log(c); } // A // (empty) // 𠮷 // (empty) // BCopy the code
Codepoint can be understood as character-based, and for what that is, see the chapter on strings.
The NodeList iterator
Previously, to iterate over NodeList (a collection of elements), we used the for loop:
// You can do thatfor (var i=0, len=NodeList; i<len; i++) {
var el = NodeList[i]
// ....
}
Copy the code
ES6 can do this directly:
for (letEl of NodeList) {// el is every element in the set}Copy the code
In addition, NodeList now has a forEach method
Spread the operator
Expansion operator.
And iterable
The expansion operator can be used on any iterable and determines which value to take based on the iterable’s default iterator.
For example, we can convert a string into an array:
[...'A 𠮷 B'] / ['A'.'𠮷'.'B']
Copy the code
conclusion
We start with the problem of the for loop and explain how ES6 solves this problem, leading to the generator, and then to iterator and iterable, and the for-of that operates on iterable. In the end, the combination of for-OF in ES6 can make the operation of built-in collection more convenient.
Of course, the for loop problem may not be the cause of the original Generator, nor does the Generator only solve the for loop problem. It has many more advanced functions, which are more useful in practice, as I will discuss later.
So why am I writing this and being a clickbait? Because I’m curious. I don’t just want to know how a technology is being used right now, but I want to know why it’s being used, I want to know the context. In this way, on the one hand, we can better understand the technology, and on the other hand, we can better understand the trend of technology development. In this way, we can see clearly the front, not to run east and west, and take so many detours.
In the end, everything is just throwing bricks to attract jade, welcome everyone’s criticism and correction!
Also, how do I throw an error into the generator? Have already written, welcome fang jia correction.