一.基础知识

Generator函数是ES6出现的一种异步操作实现方案。

异步即代码分两段,但是不是连续执行,第一段执行完后,去执行其他代码,等条件允许,再执行第二段。

同步即代码连续执行。

1. Generator函数是什么?

Generator函数是一种遍历器生成函数;运行后返回一个遍历器对象。

函数内部可以看作一个状态机;可以通过遍历器的next方法遍历函数内部的各个状态。

Generator函数不是构造函数!不能使用new命令生成实例。否则报错!

但是生成的实例是Generator函数的实例对象。

function* testGen() {
  yield 1;
}
const gen = testGen();
console.log(gen instanceof testGen); //生成的对象是Generator的实例
console.log(gen.__proto__ === testGen.prototype); // 生成的实例继承原型上的属性和方法

// 运行结果 
true
true

注意:

function* testGen() {
   yield 1;
   yield 2;
}

testGen().next(); // {value:1, done:false}
testGen().next(); // {value:1, done:false}
// 上面没有连续执行是因为,每次调用testGen方法都生成一个新的遍历器;如果想连续执行;可以将其赋值给一个变量,操作变量

构造函数本质是通过new命令,返回this对象,即实例对象。

但是Generator函数不返回this,它返回遍历器。通过直接执行返回。

此时函数内部的this是函数执行时所在的对象,即window(非严格模式,严格模式下是undefined)

<script type="module">
  function* testGen() {
    console.log(this);
  }
  const gen = testGen();
  gen.next();
</script>
  // 运行结果如下(严格模式)
  undefined

如果想要生成的遍历器对象可以访问this的属性和方法,可以使用call或者apply方法绑定this到其原型对象上。

  function* testGen() {
    this.a = 5;
    return this;
  }
  const gen = testGen.call(testGen.prototype);
  const thisObj = gen.next().value;// gen.next().value === testGen.prototype
  console.log(thisObj.a); // 5

2. Generator函数声明

1.作为函数声明

function* fnName() { // function和函数名称之间有一个*, 通常紧跟function后
  yield 表达式; // 函数内部使用yield命令
  return val; //表示最后一个状态
}
const myGenerator = fnName(); //生成遍历器对象;相当于指向内部状态的指针对象

其中,*是Generator函数的标识;yield(“产生”)是状态生成命令。

2. Generator函数作为对象的属性声明

const obj = {
  *testGen() {
    ...
  }
}
// 相当于 
const obj = {
  testGen: function* () {
    ...
  }
}

3. Generator函数生成遍历器对象

调用Generator函数后,会返回一个遍历器对象;但是此时函数内部代码并不执行。

遍历器对象可以通过自身的next方法访问Generator函数内部的状态。

yield命令除了表示生成状态,还表示暂停标识,即next方法遇到yield命令即停止运行。

所以next()方法表示从代码起始或者上一次停止的位置运行到下一个yield或者return或者代码结束。

next方法返回结果格式如下:

{value: 值, done: true/false} 
// value是当次运行的状态,即yield命令后面的表达式的值
// done表示是否遍历结束

想继续执行就要继续调用next方法,如果函数内部没有return,则一直运行到代码结束;

返回结果最后是:

{value: undefined, done: true}
//继续调用next方法,会一直返回该值

如果遇到return value,则return语句即表示遍历结束。

返回结果是:

{value: value, done: true}
//继续调用next方法,返回
{value: undefined, done: true}
// 继续调用next,一直返回该值

示例: 

function* testGen() {
  yield 1;
  return 2;
}
const gen = testGen();
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
// 运行结果如下
{value: 1, done: false}
{value: 2, done: true}
{value: undefined, done: true}
{value: undefined, done: true}

✅可以遍历遍历器状态的遍历方法

function* testGen() {
  yield 1;
  yield 2;
  yield 3;
}
const gen = testGen();
/****1. 通过扩展运算符...*******/
let result1 = [...gen]; 
console.log(result1)
/****2. 通过for...of遍历*******/
let result2 = [];
for(let item of gen) {
  result2.push(item);
}
console.log(result2)
/****3. 通过数组解构赋值********/
let [...result3] = gen;
console.log(result3)

/****4. 通过Array.from********/
let result4 = Array.from(gen);
console.log(result4)

// 运行结果如下:
[1,2,3] // 遍历器已经遍历结束,继续遍历后面会全部是[]
[]
[]
[]
一个遍历器只能遍历一遍

相关文章:

  • 2021-05-27
  • 2022-12-23
  • 2022-12-23
  • 2021-11-18
  • 2021-12-13
  • 2022-01-02
猜你喜欢
  • 2022-12-23
  • 2021-06-26
  • 2021-08-23
  • 2021-11-08
  • 2021-08-16
  • 2021-04-25
  • 2021-10-22
相关资源
相似解决方案