ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## Generator函数语法 ### 简介 #### 基本概念 `Generator` 函数是ES6提供的一种异步编程解决方案,语法行为与普通函数完全不同。 对于 `Generator` 函数有多种理解角度,从语法上,可以把它理解成一个状态机,封装了多个内部状态。 执行 `Generator` 函数会返回一个遍历器对象,所以它除了是状态机,还是一个遍历器对象生成函数,返回的遍历器对象可以依次遍历 `Generator` 函数内部的每一个状态。 形式上,`Generator` 函数是一个普通函数,但有两个特征:一是 `function` 命令与函数名之间有一个星号;二是函数体内部使用 `yield` 语句定义不同的内部状态。(`yield`:产出) ```js function* helloGenerator () { yield 'hello' yield 'Generator' return 'ending' } let hw = helloGenerator() ``` `Generator` 函数的调用方法与普通函数一样,不过的是,它并不会马上执行,返回的也不是运行结果,而是一个指向内部状态的指针对象。 接下来,必须调用遍历器对象的 `next` 方法,使得指针向下一个状态移动 。 ```js hw.next() // { value: 'hello', done: false } hw.next() // { value: 'Generator', done: false } hw.next() // { value: 'ending', done: true } hw.next() // { value: undefined, done: true } ``` #### yield表达式 `Generator` 函数返回的遍历器对象只有调用了 `next` 方法才会遍历到下一个内部状态,所以实际上它提供了一种可以暂停执行的函数,`yield` 语句就是暂停标志。 #### 与Iterator接口的关系 由于 `Generator` 函数就是遍历器生成函数,因此可以把 `Generator` 赋值给对象的 `Symbol.iterator` 属性,从而使得对象具有 `Iterator` 接口。 ```js let myIterable = {} myIterable[Symbol.iterator] = function* () { yield 1 yield 2 yield 3 } [...myIterable] // [1, 2, 3] ``` 可以被扩展运算符(...)遍历,从而生成一个数组。 #### next方法的参数 `next` 方法可以带有一个参数,该参数会被当做上一条 `yield` 语句的返回值 ### for...of循环 `for...of` 循环可以自动遍历 `Generator` 函数生成的 `Iterator` 对象,此时不再需要调用 `next` 方法。 ```js function* foo () { yield 1 yield 2 yield 3 yield 4 return 5 } for (let v of foo()) { console.log(v) } // 1 2 3 4 5 ``` 利用 `for...of` 循环,可以写出遍历任意对象的方法。原生的JavaScript对象没有遍历器接口,无法使用 `for...of` 循环,通过 `Generator` 函数为它加上接口就可以使用了。 ```js function* objectEntries(obj) { let proKeys = Reflect.ownKeys(obj) for (let proKey of proKeys) { yield [proKey, obj[proKey]] } } let jane = { first: 'Jane', last: 'Doe' } for (let [key, value] of objectEntries(jane)) { console.log(`${key}: ${value}`) } // first: Jane // last: Doe ``` 还有另外一种写法:将 `Generator` 函数加到对象的 `Symbol.iterator` 属性上。 ```js function* objectEntries () { let propKeys = Object.keys(this) for (let propKey of propKeys) { yield [propKey, this[propKey]] } } let jane = { first: 'Jane', last: 'Doe' } jane[Symobl.iterator] = objectEntries for (let [key, value] of jane) { console.log(`${key}: ${value}`) } // first: Jane // last: Doe ``` ### Generator.prototype.throw() `Generator` 函数返回的遍历器对象都有一个 `throw` 方法,可以在函数体外抛出错误,然后在 `Generator` 函数体内捕获。 ```js let g = function* () { try { yield } catch (e) { console.log('内部捕获', e) } } let i = g() i.next() try { i.throw('a') i.throw('b') } catch (e) { console.log('外部捕获', e) } // 内部捕获 a // 外部捕获 b ``` ### Generator.prototype.return() `Generator` 函数返回的遍历器对象还有一个 `return` 方法,可以返回给定的值。并终结 `Generator` 函数的遍历。 ```js function* gen () { yield 1 yield 2 yield 3 } let g = gen() g.next() // { value: 1, done: false } g.return('foo') // { value: 'foo', done: true } g.nextr() // { value: undefined, done: true } ``` ### yield* 表达式 `yield*` 语句用来在一个 `Generator` 函数中执行另一个 `Generator` 函数。 ### 作为对象属性的 Generator 函数 ### Generator 函数的 this ### 含义 #### Generator 与状态机 #### Generator 与协程 ### 应用 #### 异步操作的同步化表达 #### 控制流管理 #### 部署Iterator接口 #### 作为数据结构