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)异步操作

请查看《异步编程》

 

posted @ 2021-01-23 16:26  拉布拉多~  阅读(66)  评论(0编辑  收藏  举报