• 优雅而高效的JavaScript——Generator 函数


    在这里插入图片描述

    😎博主:小猫娃来啦
    😎文章核心:优雅而高效的JavaScript——Generator 函数

    什么是Generator函数

    Generator函数是ES6中新增的一种函数类型,它可以用来生成迭代器对象。通过使用yield关键字在函数内部暂停和恢复代码的执行,Generator函数可以实现函数的暂停和恢复。Generator函数是一种特殊类型的函数,它可以在函数执行过程中多次返回值,并且可以通过next方法控制函数的执行。


    Generator函数的基本语法

    Generator函数的定义与普通函数类似,只是在函数名前面加上了一个星号(*),如下所示:

    function* myGenerator() {
      // 函数体
    }
    
    • 1
    • 2
    • 3

    在Generator函数内部,可以使用yield关键字来暂停函数的执行,并返回一个值。yield关键字可以出现在函数的任意位置,每次执行到yield语句时,函数都会暂停执行,并将yield后面的表达式的值作为返回值返回给调用者。当再次调用next方法时,函数会从上次暂停的位置继续执行,直到遇到下一个yield语句或函数结束。


    Generator函数的运行机制

    Generator函数的运行机制与普通函数有所不同。当调用Generator函数时,并不会立即执行函数体,而是返回一个迭代器对象。通过调用迭代器对象的next方法,可以控制Generator函数的执行。

    当调用next方法时,Generator函数会执行到第一个yield语句,并将yield后面的表达式的值作为返回值返回给调用者。同时,Generator函数会暂停执行,等待下一次调用next方法。

    当再次调用next方法时,Generator函数会从上次暂停的位置继续执行,直到遇到下一个yield语句或函数结束。如果Generator函数执行到最后,没有遇到新的yield语句,那么迭代器对象的done属性会变为true,表示函数执行结束。


    Generator函数的应用场景

    惰性计算

    惰性计算是指只在需要的时候才计算结果。Generator函数可以通过yield语句的使用,实现惰性计算的效果。在每次调用next方法时,可以根据需要计算并返回结果,而不是一次性计算所有结果。

    例如,我们可以使用Generator函数来实现一个斐波那契数列的生成器:

    function* fibonacci() {
      let a = 0;
      let b = 1;
      while (true) {
        yield a;
        [a, b] = [b, a + b];
      }
    }
    
    const fib = fibonacci();
    console.log(fib.next().value); // 0
    console.log(fib.next().value); // 1
    console.log(fib.next().value); // 1
    console.log(fib.next().value); // 2
    console.log(fib.next().value); // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在上面的代码中,fibonacci函数是一个Generator函数,通过yield语句返回斐波那契数列的每一项。每次调用next方法时,都会计算并返回下一项的值。

    异步操作

    Generator函数可以用于处理异步操作,通过yield语句的使用,可以使异步操作的代码看起来像同步操作一样。

    例如,我们可以使用Generator函数来实现一个异步任务的执行器:

    function* asyncTask() {
      const result1 = yield asyncOperation1();
      const result2 = yield asyncOperation2(result1);
      return result2;
    }
    
    function asyncOperation1() {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve('result1');
        }, 1000);
      });
    }
    
    function asyncOperation2(value) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(`result2: ${value}`);
        }, 1000);
      });
    }
    
    const task = asyncTask();
    task.next().value.then((result1) => {
      task.next(result1).value.then((result2) => {
        console.log(result2); // result2: result1
      });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在上面的代码中,asyncTask函数是一个Generator函数,通过yield语句暂停函数的执行,并等待异步操作的结果。每次调用next方法时,都会执行下一个异步操作,并将上一个异步操作的结果传递给下一个异步操作。

    迭代器

    Generator函数可以用来实现迭代器。通过yield语句的使用,可以方便地生成一个可迭代对象。

    例如,我们可以使用Generator函数来实现一个简单的迭代器:

    function* myIterator() {
      yield 1;
      yield 2;
      yield 3;
    }
    
    const iterator = myIterator();
    console.log(iterator.next().value); // 1
    console.log(iterator.next().value); // 2
    console.log(iterator.next().value); // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在上面的代码中,myIterator函数是一个Generator函数,通过yield语句返回迭代器的每一项。每次调用next方法时,都会返回迭代器的下一项。


    Generator函数与普通函数的区别

    Generator函数与普通函数在语法上有一些区别:

    • Generator函数的定义在函数名前面有一个星号(*)。
    • Generator函数内部可以使用yield关键字来暂停函数的执行,并返回一个值。
    • Generator函数返回的是一个迭代器对象,而不是一个具体的值。

    Generator函数的注意事项
    在使用Generator函数时,需要注意以下几点:

    • Generator函数不能使用箭头函数的语法定义,只能使用function关键字定义。
    • Generator函数内部不能使用箭头函数,因为箭头函数没有自己的this和arguments,而Generator函数内部的yield语句需要依赖this和arguments。
    • Generator函数不能使用new关键字调用,因为Generator函数返回的是一个迭代器对象,而不是一个构造函数。

    示例代码

    下面是一个完整的示例代码,演示了Generator函数的基本用法和应用场景:

    // 惰性计算
    function* fibonacci() {
      let a = 0;
      let b = 1;
      while (true) {
        yield a;
        [a, b] = [b, a + b];
      }
    }
    
    const fib = fibonacci();
    console.log(fib.next().value); // 0
    console.log(fib.next().value); // 1
    console.log(fib.next().value); // 1
    console.log(fib.next().value); // 2
    console.log(fib.next().value); // 3
    
    // 异步操作
    function* asyncTask() {
      const result1 = yield asyncOperation1();
      const result2 = yield asyncOperation2(result1);
      return result2;
    }
    
    function asyncOperation1() {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve('result1');
        }, 1000);
      });
    }
    
    function asyncOperation2(value) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(`result2: ${value}`);
        }, 1000);
      });
    }
    
    const task = asyncTask();
    task.next().value.then((result1) => {
      task.next(result1).value.then((result2) => {
        console.log(result2); // result2: result1
      });
    });
    
    // 迭代器
    function* myIterator() {
      yield 1;
      yield 2;
      yield 3;
    }
    
    const iterator = myIterator();
    console.log(iterator.next().value); // 1
    console.log(iterator.next().value); // 2
    console.log(iterator.next().value); // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    通过使用Generator函数,我们可以实现惰性计算、异步操作和迭代器等功能,使代码更加简洁和易于理解。同时,我们也需要注意Generator函数的语法和使用注意事项,以充分发挥其功能和优势。

    在这里插入图片描述


  • 相关阅读:
    【scikit-learn基础】--『监督学习』之 均值聚类
    Scala 简介一
    07 内核开发-避免命名冲突经验技巧分享
    XTU-OJ 1412-Rotate Again
    【828. 统计子串中的唯一字符】
    基于SSM+Vue的体育馆管理系统的设计与实现
    技术研发类岗位招聘的人才测评方案
    axios的两种请求方法
    RocketMQ消息消费(Consumer)源码解析
    镜像的基本命令(docker)
  • 原文地址:https://blog.csdn.net/dyk11111/article/details/133882079