• Generator函数


    一、作用

    提供异步编程方案

    二、特点

      (1)状态机。封装了多个状态,通过yield表达式进行定义

            function* g(){
                while(true){
                    yield true;
                    yield false;
                }
                
            }
    
            const obj = g();
            console.log(obj.next()); // {value: true, done: false}
            console.log(obj.next()); // {value: false, done: false}
            console.log(obj.next()); // {value: true, done: false}
            console.log(obj.next()); // {value: false, done: false}

      (2)是一个遍历器对象生成函数(不理解可以看遍历器),总是返回一个遍历器,ES6规定这个遍历器是 Generator 函数的实例,也继承了 Generator 函数的prototype对象上的方法。但是this的指向为window,可以通过 call() 修改 this 的指向。

            function* g(){
                console.log("start");
                this.a = 1;
                yield this.b = 2;
                yield this.c = 3;
            }
    
            g.prototype.hello = function () {
                console.log('a');
            }
    
            const obj = g();
            console.log(obj instanceof g); // true     (obj是g的实例)
            obj.hello(); // a    (实例继承了prototyped上的方法,这个特点跟我们自己创建一个class的效果是一样的)
            obj.next(); // 至少要调用一次,不然g()里面的代码都没有执行;
            console.log(obj.a); // undefined    
            console.log(window.a); // 1
    
            //修改 this 的指向
            const newObj = g.call(g.prototype);
            newObj.hello(); // a
            newObj.next();
            console.log(newObj.a); // 1
            console.log(newObj.b); // 2
            console.log(newObj.c); // undefined   (因为还没执行到this.c = 3)

    二、语法

      (1)function 和 函数名之间有一个星号,能区别于其他的普通函数

      (2)函数体内部使用yield表达式,起到暂停的作用。(yield只能在Generator函数里使用,普通函数使用会报错)yield表达式如果用在另一个表达式之中,必须放在圆括号里面。

          如果在一个Generator函数里面要调用另一个Generator函数,要写成 yield* F() , 等同于调用了for....of.....

    function* P(){
                yield 'a';
                yield 'b';
                yield 'c';
            }
    
            function* S(){
                yield 'd';
                yield* P();
                yield 'e';
            }
    
            function* S1(){
                yield 'd';
                for(let value of P()){
                    yield value;
                }
                yield 'e';
            }
    
            const s = S();
            console.log(s.next());      // {value: "d", done: false}
            console.log(s.next());      // {value: "a", done: false}
            console.log(s.next());      // {value: "b", done: false}
            console.log(s.next());      // {value: "c", done: false}
            console.log(s.next());      // {value: "e", done: false}
            console.log(s.next());      // {value: undefined, done: true}
    
            const s1 = S1();
            console.log(s1.next());      // {value: "d", done: false}
            console.log(s1.next());      // {value: "a", done: false}
            console.log(s1.next());      // {value: "b", done: false}
            console.log(s1.next());      // {value: "c", done: false}
            console.log(s1.next());      // {value: "e", done: false}
            console.log(s1.next());      // {value: undefined, done: true}

      (3)执行到return之后,遍历就结束了,即使后面还有yield表达式也是无效。

            function* gerenator(arr){
                for (let value of arr) {
                    yield value;
                }
                return 'ending';
                yield 111;
            }
    
            const g = gerenator(['a','b']);
            console.log(g.next());  //{value "a", done: false}
            console.log(g.next());  //{value "b", done: false}
            console.log(g.next());  //{value "ending", done: true}
            console.log(g.next());  //{value undefined, done: true}
    View Code

      (4)next方法的参数会被当作上一个yield表达式的返回值。

    function* generator(arr){
                for(let item of arr){
                    let bool = yield item;
                    if(bool){
                        return;
                    }
                }
            }
    
            const arr = ['a','b','c','d'];
            const g = generator(arr);
    
            console.log(g.next());      // {value: 'a', done: false}
            console.log(g.next());      // {value: 'b', done: false}
            console.log(g.next(true));      // {value: undefined, done: true}
            console.log(g.next());      // {value: undefined, done: true}

    三、API

    1.Generator.prototype.throw()

      (1)作用:捕获函数体外抛出的错误

      (2)必须至少执行一次next()之后才能进行捕获

      (3)捕获后,会附带执行一次next方法

            function* generator(){
                try {
                    yield 'a';
                    yield 'b';
                    yield 'c';
                } catch (err) {
                    console.log(`内部捕获:${err}`);
                }
                yield 'zxn';
                yield 'zxn1';
            }
    
            const g = generator();
            try {
                console.log(g.next());      // {value: 'a', done: false}
                console.log(g.throw("第一次出错"));      // 内部捕获:第一次出错     {value: 'zxn', done: false}
                console.log(g.next());      // {value: 'zxn1', done: false}
                console.log(g.throw("第二次出错"));  // 外部捕获:第二次出错
            } catch (err) {
                console.log(`外部捕获:${err}`);
            }

    2.Generator.prototype.return()

      (1)可以返回特定的值,并结束遍历器(如果有try......finally,会提前进入finally中)

    function* generator(){
                try {
                    yield 'a';
                    yield 'b';
                    yield 'c';
                } catch (err) {
                    console.log(`内部捕获:${err}`);
                } finally {
                    yield 'F1';
                    yield 'F2';
                }
                yield 'zxn';
                yield 'zxn1';
            }
    
            const g = generator();
            console.log(g.next());      // {value: 'a', done: false}
            console.log(g.return('结束,提前进入finally'));        // {value: 'F1', done: false}
            console.log(g.next());      // {value: 'F2', done: false}
            console.log(g.next());      // {value: "结束,提前进入finally", done: true}
            console.log(g.next());      // {value: undefined, done: false}

    3.Generator.prototype.next()

      只有开始调用next()方法的时候,才会开始执行遍历器里面的代码,遇到yield或return就会返回。执行完return之后遍历器就结束了

    四、应用

    (1)部署Iterator接口

            const obj = {id: 1, name: "zheng", con: "content"};
            obj[Symbol.iterator] = function* (){
                for(let value in this){
                    yield this[value];
                }
                return "ending";
            }
    
            for(let value of obj){
                console.dir(value);  // 1     zheng    content
            }
    View Code

     (2)异步操作

    请查看《异步编程》

  • 相关阅读:
    作用域随笔
    关于取数组地址的识记(&s+1,s+1,&s[0]+1)
    c中关于#与##的简易使用
    Qt Creator的配置
    sizeof对int long double char的使用
    i++与++i的区别
    for循环执行顺序
    gcc 编译的4个过程简单识记
    各进制之间转化识记
    删除临时文件
  • 原文地址:https://www.cnblogs.com/zxn-114477/p/14286826.html
Copyright © 2020-2023  润新知