ES6中Generator函数

1.Generator介绍

声明:Generator函数是ES6提供的一种异步编程的解决方案,可以看成一个状态机,封装了多个内部状态,执行Generator函数会返回一个遍历器对象,所以也是遍历器对象生成函数。 Generator函数也是一个普通函数,但是有两个特征。第一是funtction关键字与函数名之间有个*,第二是函数体内部使用yield表达式,定义不同的内部状态。

 function* fun() {
            yield "张三"  //状态1
            yield "李四"  //状态2
            return "结束" //状态3
        }
        const obj = fun()
        console.log(obj); //fun {<suspended>}

声明: 返回的是一个指向内部状态的指针对象,也就是遍历器对象。

2.Generator 函数是分段执行

声明:Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。

   console.log(obj.next()); //{value: '张三', done: false}
        console.log(obj.next()); //{value: '李四', done: false}
        console.log(obj.next()); //{value: '结束', done: true}
        // 第三次调用Generator函数从上次yield表达式停下的地方,一直执行到下一个yield表达式。如果有retrun就执行到retrun
        console.log(obj.next()); //{value: undefined, done: true}

3. yield表达式

声明:一种可以暂停函数的标志的表达式,只有调用next()方法,内部指针指向该语句才执行。我们可以看成一种惰性求值的语法功能。

  function* fun2(a, b) {
            yield a + b
            return a * 5
        }
        const obj2 = fun2(5, 6)
        console.log(obj2); //fun2 {<suspended>}
        console.log(obj2.next()); //{value: 11, done: false}
        console.log(obj2.next()); //{value: 25, done: true}
        console.log(obj2.return(5)); //{value: 5, done: true}

注意:return与yield区别,一个函数里面只能有一个return语句。

4.特殊形式

 说明:Genrator函数可以不用yield表达式,这时就变成了一个单纯的暂缓执行函数。

 function* fun3() {
            console.log("Hello world");
        }
        console.log(fun3().next());
        //Hello world
        //{value: undefined, done: true}

5.yield表达注意点

  1. yield表达式,只能在Generator函数里面。
  2. yield表达式如果用在另一个表达式之中,必须放在圆括号里。
 function* fun4() {
            console.log("你好" + (yield 123));
            console.log("你好" + (yield 234));
        }
        const obj4 = fun4()
        console.log(obj4.next()); //{value: 123, done: false}
        console.log(obj4.next()); //{value: 234, done: false}

6.与Iterator接口的关系

说明:由于Generator函数就是遍历器生成函数,因此可以把Geneartor赋值给等下给对象的Symbol.iterator属性,从而使得该对象具有Iterator接口。

  const myIter = {}
        myIter[Symbol.iterator] = function* fun5() {
            yield 1
            yield 2
            return 3
        }
        console.log(...myIter);
        //1 2 

 说明:没有3这个结果,说明只会遍历yield声明的表达式。(是因为返回对象的done属性为true,for...of循环就会中止)

7.Generator函数时遍历器函数

const fun6 = function* () {

        }
        const newFun6 = fun6()
        console.log(newFun6 === newFun6[Symbol.iterator]()); //true

8. next方法的参数

说明:next方法可以带一个参数,该参数就会当成一个yield表达式的返回值。

 function* fun7(x) {
            let a = 4 * (yield (x + 1))
            let b = yield (a / 3)
            return (a + b + x)
        }
        const obj5 = fun7(1)
        console.log(obj5.next()); //{value: 2, done: false}
        console.log(obj5.next()); //{value: NaN, done: false}
        console.log(obj5.next()); //{value: NaN, done: true}
        // 第二次运行next()方法的时候不带参数,导致4*undefined等于NaN

        const obj6 = fun7(2)
        console.log(obj6.next()); //{value: 3, done: false}
        console.log(obj6.next(2)); //{value: 2.6666666666666665, done: false}
        console.log(obj6.next(3)); //{value: 13, done: true}

说明:next方法的参数表示上一个yield表达式的返回值,所以在第一次使用next方法,是不需要参数的。v8引擎直接忽略第一个使用的next()方法,只有第二次使用next()方法开始,参数还是有效的。

9.for ...of 循环

说明:for...of循环可以自动遍历Genrator函数运行时生成的Iterator对象,且此时不再需要调用next()方法。

     function* fun8() {
            yield 1
            yield 2
            yield 3
            return 4
        }
        for (let i of fun8()) {
            console.log(i);
            //1
            //2
            //3
        }

注意:不遍历return是因为返回对象的done属性为true,for...of循环就会中止,且不包含该返回对象。

10.Generator.prototype.throw

说明:Generator函数返回的遍历器对象,可以有throw方法,可以在函数Generartor函数体内捕获。

    const fun9 = function* () {
            try {
                yield
            } catch (error) {
                console.log("内部捕获", error);
            }
        }
        const obj8 = fun9()
        obj8.next()
        try {
            obj8.throw("错误1")
            obj8.throw("错误2")
        } catch (error) {
            console.log("外部捕获", error);
        }
        //内部捕获 错误1
        //外部捕获 错误2

说明:由于Generator函数内部的catch语句已经执行过了,就不会捕获到这个错误了,然后抛出了Generator函数体。

11.Genrator.prototype.return

说明:Generator 函数返回的遍历器函数,还有一个return方法,可以返回指定值,并终结Generator函数。

     function* fun10() {
            yield 1
            yield 2
        }
        const obj10 = fun10()
        console.log(obj10.next()); //{value: 1, done: false}
        console.log(obj10.return(10));//{value: 10, done: true}
        console.log(obj10.next()); //{value: undefined, done: true}

12.try...finally

说明:使用try...finally代码块,且正在执行try代码块那么return()方法会导致立刻进入finally代码块,执行完,整个函数才会结束。

  function* fun11() {
            try {
                yield 1
                yield 2
            } finally {
                yield 10
                yield 20
            }
        }
        const obj11 = fun11()
        console.log(obj11.next()); //1
        console.log(obj11.return(10)); //{value: 10, done: false}
        console.log(obj11.next()); //{value: 20, done: false}

13. next(),throw(),return()共同点

说明:其实作用时Generator函数恢复执行,并且使用不同语句替换yield表达式。

14.yield*表达式

说明: 解决Generator函数里面执行另一个Generator函数。

 function* fun12() {
            yield 2
            yield 3
        }
        function* fun13() {
            yield 4
            yield* fun12()
            yield 5
        }
        //    等价于
        function* fun13() {
            yield 4
            yield 2
            yield 3
            yield 5

        }

15.对象属性的Generator函数

说明:如果对象的属性时Generator函数,可以简写成下面的形式。

  const obj12 = {
            *fun14() {

            }
        }

16.Generator函数的this

说明:因为Generator函数总是返回一个遍历器,它就是Generator函数的实例。要改变可以通过call方法,apply方法等修改this的指向。

   function* fun15() {
            this.a = 666
            yield 1

        }
        const obj14 = {
     
        }
        const obj15 = fun15()
        obj15.next()
        console.log(obj15.a); //undefined
        // 改变this
        const obj16 = fun15.call(obj14)
        console.log(obj16.next());//{value: 1, done: false}
        console.log(obj14.a);

注意:构造函数调用以后,这个空对象就是 Generator 函数的实例对象了。

猜你喜欢

转载自blog.csdn.net/m0_62785037/article/details/130779082