ES6: The Ins and Outs of Generator

ES6: The ins and outs of Generator

Overview

  • Generator function is an asynchronous programming solution provided by ES6. It can be understood as a state machine that encapsulates multiple internal states. -

  • Executing the Generator function will return a iterator object, which can traverse each state inside the function in turn;

  • The Generator function has two characteristics:

    • There is an asterisk between function and function name;
    • The yield statement is used inside the function body to define different internal states.
  • Example:

    function*helloWorldGenerator(){
          
          
        yield '听不见!';
        yield '重来!';
        return '很有精神!'
    }
    let hw = helloWorldGenerator();
    
    hw.next();	// { value : '听不见!',done : false }
    hw.next();	// { value : '重来!',done : false }
    hw.next();	// { value : '很有精神!',done : true }
    hw.next();	// { value : undefined , done : true }
    
  • Using this feature, you can realize the asynchronous programming mechanism of the function;

yield expression

  • The running mechanism of the next method of the traverser is as follows:

    1. When encountering a yield statement, the execution of the following operations will be suspended, and the value of the yield expression will be returned as the value attribute value of the returned object;
    2. The next time the next call is called to continue execution, until the next yield statement is encountered;
    3. If there is no yield, run directly to the return statement;
    4. If there is no return statement, an object whose value is undefined is returned.
  • Yield must be placed in the Generator function before it can be used;

  • If yield is used in another expression, parentheses must be added!

    console.log('hello' + yield 123); ///error
    console.log('hello' + (yield 123));  //ok 
    

Parameters of the next method

  • The next method can take a parameter, which will be used as the return value of the previous statement. When next has no parameters, it returns undefined;

    function* f(){
          
          
        for(let i=0;ture;i++){
          
          
            let reset = yield i;
            if(reset){
          
          
                i = -1;
            }
        }
    }
    
    let g = f();
    g.next()	//{value : 0,done : false};
    g.next()	//{value : 1,done : false};
    g.next(true)	//{value : 0,done : false};
    

for...of method

  • The for...of loop can automatically traverse the Iterator object generated by the Generator function, eliminating the need to use the next method;

    function* foo(){
          
          
        yield 1;
        yield 2;
        yield 3;
        yield 4;
        yield 5;
    }
    
    for (let v of foo()){
          
          
        console.log(v);
    }
    

yield* expression

  • If you call another Generator function in a Generator, the default is no effect;

    function* foo(){
          
          
        yield 'a';
        yield 'b';
    }
    
    function bar(){
          
          
        yield 1;
        foo();
        yield 2;
    }
    
    for(let i of bar()){
          
          
        console.log(i);
    }
    
    >>1
    >>2
    
  • It can be seen that the direct call cannot execute foo() in for...of;

  • At this time, you need to use the yield* statement, so the above code can be modified as follows:

    function* foo(){
          
          
        yield 'a';
        yield 'b';
    }
    
    function bar(){
          
          
        yield 1;
        yield* foo();
        yield 2;
    }
    
    for(let i of bar()){
          
          
        console.log(i);
    }
    
    >>1
    >>'a'
    >>'b'
    >>2
    
  • If yield* is followed by an array, the members of the array will be traversed:

    function* foo(){
          
          
        yield [1,2,3,4,5];
    }
    foo().next();	//[1,2,3,4,5]
    
    function* foo(){
          
          
        yield* [1,2,3,4,5];
    }
    foo().next();	//{value : 1,done : false}
    
  • The yield* expression can quickly traverse all the members of the nested array;

    function* iterTree(tree){
          
          
        if(Array.isArray(tree)){
          
          
            for(let i=0;i<tree.length;i++);
            yield* iterTree(tree[i]);
        }else{
          
          
            yield tree;
        }
    }
    
    
    const tree = [1,[2,3],[4,5]];
    for(let x of iterTree(tree)){
          
          
        console.log(x);
    }
    
    >> 1
    >> 2
    >> 3
    >> 4
    >> 5
    

This of the Generator function

  • The iterator returned by the Generator function is an instance of the original Generator function, which also inherits the prototype of the original function;

  • Therefore, the iterator of the Generator function cannot directly access the properties of the original function;

    function* foo(){
          
          
        this.a = 1;
    }
    
    let obj = foo();
    console.log(obj.a);			//undefined
    
  • To obtain the properties of the original function, you can obtain it through a flexible method-use the call method to bind this inside the Generator function;

    function* foo(){
          
          
        this.a = 1;
        yield this.b = 2;
        yield this.c = 3;
    }
    let obj = {
          
          };
    let bar = foo.call(obj); 
    
    bar.next();		//{value : 2 , done : false};
    bar.next();		//{value : 3 , done : false};
    
    console.log(obj.a)	// 1
    console.log(obj.b)	// 2
    console.log(obj.c)	// 3
    

Guess you like

Origin blog.csdn.net/yivisir/article/details/108476987