前端面试题库

ES6中Generator的理解

Generator更新时间:2024-09-13 12:16:58

答案

Generator的概念

Generator是ES6提供的异步编程解决方案,语法行为与传统的函数不同,可以将它理解成一个状态机,封装了多个内部状态。

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

  1. function关键字与函数名之间有一个星号;
  2. 函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator();

调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,就是遍历器对象。

必须调用next方法,使得指针移到下一个状态,每次调用next方法,内部指针从函数头部或者上一次停止的地方开始执行,直到遇到yield表达式,yield后面的表达式的结果作为本次执行的value,并且返回迭代是否完成的状态done;如果遇到return就将return后面表达式的值作为返回值,同时done=true,如果函数没有returnvalue就是undefined。

如果Generator函数执行完毕,再次调用next,返回结果为{ value: undefined, done: true }

hw.next(); // { value: 'hello', done: false } hw.next(); // { value: 'world', done: false } hw.next(); // { value: 'ending', done: true } hw.next(); // { value: undefined, done: true }

与Iterator的关系

Generator函数会返回一个迭代器对象,该对象具有Symbol.iterator属性,执行后返回自身。

function* gen(){ // some code } var g = gen(); g[Symbol.iterator]() === g // true

因此可以把Generator函数设置给对象的Symbol.iterator属性,从而使该对象具有iterator接口,

var myIterable = {}; myIterable[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; }; [...myIterable] // [1, 2, 3]

for...of循环

for...of可以自动遍历Generator函数运行时生成的对象,所以不需要手动调用next方法。注意一旦next返回对象的donetrue,for...of循环就会停止,并且不包含该返回对象。所以下面的例子中6没有被打印出来。

function* foo() { yield 1; yield 2; yield 3; yield 4; yield 5; return 6; } for (let v of foo()) { console.log(v); } // 1 2 3 4 5

同时for...of可以遍历具有Symbol.iterator属性的对象。

var myIterable = { [Symbol.iterator]: function* () { yield 1; yield 2; yield 3; } }; for (let value of myIterable) { console.log(value);// 1 2 3 }

Generator函数嵌套使用

ES6提供了yield*表达式,用来在一个 Generator 函数里面执行另一个 Generator 函数。

function* foo() { yield 'a'; yield 'b'; } function* bar() { yield 'x'; yield* foo(); yield 'y'; } // 等同于 function* bar() { yield 'x'; yield 'a'; yield 'b'; yield 'y'; } // 等同于 function* bar() { yield 'x'; for (let v of foo()) { yield v; } yield 'y'; } for (let v of bar()){ console.log(v); }

评论