MEMEPh. ideas that are worth sharing...

ES6 iterators and generators

1. Iterator


JavaScript's original data structures that represent "collections" are mainly arrays and objects. ES6 adds Map and Set. This requires a unified interface mechanism to handle all the different data structures. Iterators are one such mechanism. It is an interface that provides a unified access mechanism for a variety of different data structures. Any data structure can complete the traversal operation (ie, process all members of the data structure in turn) as long as the Iterator interface is deployed .

 

1. The role of Iterator:

Provide a unified and convenient access interface for various data structures;

Enables members of a data structure to be arranged in a certain order

ES6 created a new traversal command for...of loop, and the Iterator interface is mainly used for for...of consumption.

 

2. Native data with iterator interface (for of traversal)

let arr3 = [1, 2, 'kobe', true];
for(let i of arr3){
   console.log(i); // 1 2 kobe true
}
let str = 'abcd';
for(let item of str){
   console.log(item); // a b c d
}  
function fun() {
    for (let i of arguments) {
       console.log(i) // 1 4 5
    }
}
fun(1, 4, 5)
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
  console.log(e);
}
// Gecko
// Trident
// Webkit    

 

3. How iterators work

 

4. Write an iterator by hand

function myIterator(arr) {
let nextIndex = 0
return {
next: function() {
return nextIndex < arr.length
{ value: arr[nextIndex++], done: false }
: { value: undefined, done: true }
} 
} 
} 

let arr = [1, 4, 'ads']// prepare a data
let iteratorObj = myIterator(arr)
console.log(iteratorObj.next()) // All iterator objects have a next() method, which returns a result object
console.log(iteratorObj.next())
console.log(iteratorObj.next())
console.log(iteratorObj.next())

 

5. Notes

① for of loop does not support traversal of ordinary objects

var obj = { a: 2, b: 3 }
   for (let i of obj) {
     console.log(i) // Uncaught TypeError: obj is not iterable
}

The object's Symbol.iterator property, pointing to the object's default iterator method. When using for of to traverse a data structure, first go to Symbol.iterator, and traverse if you find it. If you don't find it, you can't traverse it.Uncaught TypeError: XXX is not iterable

② When using the spread operator (...) or destructuring assignments to arrays and Set structures, the Symbol.iterator method will be called by default

let arr1 = [1,3]
let arr2 = [2,3,4,5]
arr2 = [1,...arr2,6]
console.log(arr2) // [1, 2, 3, 4, 5, 6]

 

2. Generator


1. Concept

2. Features

function* generatorExample(){
console.log("Start execution")
yield 'hello';
yield 'generator';
} 
// generatorExample()
// This call method Generator function will not execute
let MG = generatorExample() // return pointer object
MG.next() //Start execution {value: "hello", done: false}

The Generator function is executed in sections. The internal logic of the function calling the next method starts to execute. When the yield expression is encountered, it stops and returns {value: expression result after yield/undefined, done: false/true}. Calling the next method again will start from the yield at the last stop until the end.

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();
hw.next()// { value: 'hello', done: false }
hw.next()// { value: 'world', done: false }
hw.next()// { value: 'ending', done: true }
hw.next()// { value: undefined, done: true }

On the first call, the Generator function starts executing until the first yield expression is encountered. The next method returns an object whose value attribute is the value of the current yield expression hello, and the value of the done attribute is false, indicating that the traversal has not ended.

On the second call, the Generator function continues from where the last yield expression left off until the next yield expression. The value attribute of the object returned by the next method is the value world of the current yield expression, and the value of the done attribute is false, indicating that the traversal has not ended.

In the third call, the Generator function executes from the place where the last yield expression stopped until the return statement (if there is no return statement, it executes until the end of the function). The value property of the object returned by the next method is the value of the expression immediately following the return statement (if there is no return statement, the value of the value property is undefined), and the value of the done property is true, indicating that the traversal has ended.

The fourth call, the Generator function has finished running, the value property of the object returned by the next method is undefined, and the done property is true. Calling the next method later will return this value.

 

3. next pass parameters

The yield expression itself does not return a value, or it always returns undefined. The next method can take one parameter, which will be used as the return value of the previous yield expression.

function* generatorExample () {
console.log('Start execution')
let result = yield 'hello'
console.log(result)
yield 'generator'
}
let MG = generatorExample()
MG.next()
MG.next()
// start execution
// undefined
// {value: "generator", done: false}

When no value is passed, result is undefined by default. Next, we pass a parameter to the second next, and see what the output is?

function* generatorExample () {
console.log('Start execution')
let result = yield 'hello'
console.log(result)
yield 'generator'
}

let MG = generatorExample()
MG.next()
MG.next(11)
// start execution
// 11
// {value: "generator", done: false}

 

4. Relationship with the Iterator interface

We mentioned above that the object does not have an iterator interface, and an error will be reported when traversing with for...of.

let obj = { username: 'kobe', age: 39 }
for (let i of obj) {
  console.log(i) //  Uncaught TypeError: obj is not iterable
}

Since the Generator function is the traverser generating function, the Generator can be assigned to the Symbol.iterator property of the object, so that the object has the Iterator interface .

let obj = { username: 'kobe', age: 39 }
obj[Symbol.iterator] = function* myTest() {
  yield 1;
  yield 2;
  yield 3;
};
for (let i of obj) {
  console.log(i) // 1 2 3
}

In the above code, the Generator function is assigned to the Symbol.iterator property, so that the obj object has the Iterator interface and can be traversed by for of.

 

5.Generator's asynchronous application

Business needs:

How to implement (the front-end core code is as follows): 

function* sendXml() {
// url is the data passed in by next
let url = yield getNews('http://localhost:3000/news?newsId=2');//Get news content
yield getNews(url);//Get the corresponding news comment content, only by first getting the news data and piecing it together into a url, can you make a request to the background
} }

function getNews(url) {
$.get(url, function (data) {
console.log(data);
let commentsUrl = data.commentsUrl;
let url = 'http://localhost:3000' + commentsUrl;
// When the news content is successfully obtained, send a request to obtain the corresponding comment content
// Call next to pass the meeting as the return value of the yield from the last pause
sx.next(url);
})
} 
let sx = sendXml();// Send a request to get news content
sx.next();