es6--Generator 函数语法

目录

一、概述

1.1 简介

1.2 Generator函数和普通函数区别

1.3 如何定义Generator函数

1.4 示例

二、yield 表达式

2.1 遍历器对象的next方法的运行逻辑

2.2 注意

2.3 示例

三、应用场景

3.1 让函数返回多个值

3.2 利用 Generator 函数,可以在任意对象上快速部署 Iterator 接口

3.3 用同步的流程来表示异步的操作(了解)


 

一、概述

1.1 简介

  • Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
  • 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态
  • 执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数
  • 返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态


1.2 Generator函数和普通函数区别

调用Generator函数后, 无论函数有没有返回值, 都会返回一个迭代器对象,

调用Generator函数后, 函数中封装的代码不会立即被执行


1.3 如何定义Generator函数

形式上,Generator 函数是一个普通函数,但是有两个特征:

只需要在普通函数的function后面加上*即可

函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)


1.4 示例

示例1:

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

var hw = helloWorldGenerator();

解释:

  • 上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)
  • Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号
  • 不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象

下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态

也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止

换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

解释:

第一次调用,Generator 函数开始执行,直到遇到第一个yield表达式为止。next方法返回一个对象,它的value属性就是当前yield表达式的值hello,done属性的值false,表示遍历还没有结束

第二次调用,Generator 函数从上次yield表达式停下的地方,一直执行到下一个yield表达式。next方法返回的对象的value属性就是当前yield表达式的值world,done属性的值false,表示遍历还没有结束

第三次调用,Generator 函数从上次yield表达式停下的地方,一直执行到return语句(如果没有return语句,就执行到函数结束)。next方法返回的对象的value属性,就是紧跟在return语句后面的表达式的值(如果没有return语句,则value属性的值为undefined),done属性的值true,表示遍历已经结束

第四次调用,此时 Generator 函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true。以后再调用next方法,返回的都是这个值

示例2:

    function* gen() {
        console.log("123");
        let res = yield "aaa"; //传参
        // yield "aaa";

        console.log(res); //传参
        console.log("567");
        yield 1 + 1;

        console.log("789");
        yield true;
    }

    let it = gen();
    // console.log(it);
    console.log(it.next());
    // 传参
    console.log(it.next("it666"));
    // console.log(it.next());
    // console.log(it.next());
    // console.log(it.next());


二、yield 表达式

由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志

2.1 遍历器对象的next方法的运行逻辑

  1. 遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值
  2. 下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式
  3. 如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值
  4. 如果该函数没有return语句,则返回的对象的value属性值为undefined


2.2 注意

yield表达式后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为 JavaScript 提供了手动的“惰性求值”(Lazy Evaluation)的语法功能

yield关键字只能在Generator函数中使用, 不能在普通函数中使用


2.3 示例

<script>
        function* Demo() {
            //状态
            yield 'hi';
            yield 'xxx';
            yield 'I\' miss you very much!';
            yield 'you know?';
            return 'hello';
        }

        const demo = Demo();

        console.log(demo.next());
        console.log(demo.next());
        console.log(demo.next());
        console.log(demo.next());
        console.log(demo.next());
        console.log(demo.next());
</script>


三、应用场景

3.1 让函数返回多个值

    /*
    function calculate(a, b) {
        let sum = a + b;
        let sub = a - b;
        return [sum, sub];
    }
    或
    */

    function* calculate(a, b) {
        yield a + b;
        yield a - b;
    }
    let it = calculate(10, 5);
    console.log(it.next().value);
    console.log(it.next().value);


3.2 利用 Generator 函数,可以在任意对象上快速部署 Iterator 接口

Generator 函数特点:

1.Generator 函数也是一个函数

2.Generator 函数会返回一个迭代器对象

3.迭代器对象有next方法

4.next方法每次执行都会返回一个对象{value: xxx, done: false}

必须有一个叫做[Symbol.iterator]的属性

[Symbol.iterator]的属性会返回一个函数

[Symbol.iterator]返回的函数执行之后会返回一个可迭代对象

[Symbol.iterator]函数返回的对象中又一个名称叫做next的方法

next方法每次执行都会返回一个对象{value: xxx, done: false}

    let obj = {
        name: "lwj",
        age: 23,
        gender: "man"
    }
    function* gen(){
        let keys = Object.keys(obj);
        for(let i = 0; i < keys.length; i++){
            yield obj[keys[i]];
        }
    }
    obj[Symbol.iterator] = gen;//定义一个gen函数并赋值给 obj[Symbol.iterator]
    // console.log(obj[Symbol.iterator]);
    let it = obj[Symbol.iterator]();
    // console.log(it);
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
    for(let value of obj){
        console.log(value);
    }


3.3 用同步的流程来表示异步的操作(了解)

    function request() {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve("拿到的数据");
            }, 1000);
        });
    }
    function* gen() {
        yield request();
        yield request();
        yield request();
    }
    let it = gen();
    // console.log(it.next().value);
    it.next().value.then(function (data) {
        console.log(data, 1);
        return it.next().value;
    }).then(function (data) {
        console.log(data, 2);
        return it.next().value;
    }).then(function (data) {
        console.log(data, 3);
    });

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白小白从不日白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值