一.基础知识
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] // 遍历器已经遍历结束,继续遍历后面会全部是[] [] [] []