# ES6: Generator function ---- # 參考連結 1. [ECMAScript 6 入门 | 阮一峰](http://es6.ruanyifeng.com/#docs/generator) 2. [Egghead](https://egghead.io/lessons/ecmascript-6-generators?course=learn-es6-ecmascript-2015) 3. [淺入淺出 Generator Function](http://abalone0204.github.io/2016/05/08/es6-generator-func/) 4. [Promise, generator, async 與 ES6](http://huli.logdown.com/posts/292655-javascript-promise-generator-async-es6) 5. [Airbnb style guide](https://github.com/airbnb/javascript#iterators-and-generators) --- # 淺入淺出 Generator function ---- ## 一. 它是一個狀態機 ---- 它封裝多個內部狀態,而 yield 是一個暫停標誌 ```js function* generator() { yield 'state1'; yield 'state2'; } ``` ---- ## 二. 它會回傳一個遍歷器 ---- ```js function* speak() { yield 'hello'; yield 'world'; } const iterator = speak(); ``` ---- ## 三. 使用 `next()` 遍歷狀態 ---- ```js function* speak() { yield 'hello'; yield 'world'; } const i = speak(); i.next(); // { value: 'hello', done: false } i.next(); // { value: 'world', done: false } i.next(); // { value: undefined, done: true } ``` ---- 如果 generator 有 `return` 值 ```js function* speak() { yield 'hello'; yield 'world'; return '!'; } const i = speak(); i.next(); // { value: 'hello', done: false } i.next(); // { value: 'world', done: false } i.next(); // { value: '!', done: true } i.next(); // { value: undefined, done: true } ``` ---- `yield` 後面的表達式,只有被呼叫 `next()` 才會執行 ```js function getName() { console.log('My name is world.'); return 'world'; } function* speak() { yield 'hello ' + getName(); } const i = speak(); i.next(); // My name is world. // { value: 'hello world', done: false } ``` ---- ```js // 不一定要使用 yield function* speak() {} // 但是 yield 一定要在 generator function 中使用 function speak() { yield 'hello world'; // Error! } // 在表達式中必須加括弧 console.log('hello' + (yield 'world')); // 在參數中不用 getName(yield 'Who are you?'); ``` ---- ## 四. 在 `next()` 中傳入參數,與 generator 互動 ---- ```js function* conversation() { const name = yield 'What\'s your name?'; yield `Ok, your name is ${name}, right?`; } const i = conversation(); i.next().value; // What's your name? i.next('Jason').value; // Ok, your name is Jason, right? ``` ---- 第一個 next() 是不能給參數的 ```js const i = conversation(); i.next().value; i.next('Jason').value; ``` ---- ## 累了嗎? ---- 小試題:會印出什麼呢? ```js function* foo(x) { const y = 2 * (yield (x + 1)); const z = yield (y / 3); return (x + y + z); } const i = foo(5); console.log(i.next().value); console.log(i.next(12).value); console.log(i.next(13).value); ``` ---- ```js function* foo(x) { const y = 2 * (yield (x + 1)); const z = yield (y / 3); return (x + y + z); } const i = foo(5); console.log(i.next().value); // 6 console.log(i.next(12).value); // 8 console.log(i.next(13).value); // 42 ``` ---- ## 淺入淺出 Generator function 1. 它是一個狀態機 2. 它會回傳一個遍歷器 3. 使用 `next()` 遍歷狀態 4. 在 `next()` 中傳入參數,與 generator 互動 --- # 中入淺出 Generator function ---- ## ㄧ. for...of ---- 注意:沒有 `return` 值 ```js 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 ``` ---- 一個 fibonacci 例子 ```js function* fibonacci() { let [prev, curr] = [0, 1]; while (true) { [prev, curr] = [curr, prev + curr]; yield curr; } } for (let n of fibonacci()) { if (n > 1000) break; console.log(n); } ``` ---- ```js function* numbers () { yield 1 yield 2 return 3 yield 4 } [...numbers()] // [1, 2] Array.from(numbers()) // [1, 2] let [x, y] = numbers(); // x=1, y=2 for (let n of numbers()) { console.log(n); } // 1 2 ``` ---- ## 二. Generator.prototype.throw ---- ```js function* g() { try { yield; } catch (e) { console.log('内部捕獲', e); } } var i = g(); i.next(); try { i.throw('a'); i.throw('b'); } catch (e) { console.log('外部捕獲', e); } // 內部捕獲, a // 外部補獲, b ``` ---- `throw` 被捕獲以後,會附帶執行下一條 `yield` 語句 ```js function* g() { try { yield console.log('a'); } catch (e) { // ... } yield console.log('b'); yield console.log('c'); } var i = g(); i.next(); // a i.throw(); // b i.next(); // c ``` ---- ## 三. Generator.prototype.return ---- ```js function* g() { yield 1; yield 2; yield 3; } var i = g(); i.next(); // { value: 1, done: false } i.return('foo'); // { value: 'foo', done: true } i.next(); // { value: undefined, done: true } ``` ---- ```js function* numbers() { yield 1; try { yield 2; yield 3; } finally { yield 4; yield 5; } yield 6; } var i = numbers() i.next(); // { done: false, value: 1 } i.next(); // { done: false, value: 2 } i.return(7); // { done: false, value: 4 } i.next(); // { done: false, value: 5 } i.next(); // { done: true, value: 7 } ``` ---- ## 四. yield* ---- ```js function* foo() { yield 'a'; yield 'b'; } function* bar() { yield 'x'; yield* foo(); yield 'y'; } for (let v of bar()) { console.log(v); } // x a b y ``` ---- 陣列是 iterator ```js function* g() { yield* ['a', 'b', 'c']; } g().next() // { value: 'a', done: false } ``` 字串也是 ```js let read = (function* () { yield 'hello'; yield* 'hello'; })(); read.next().value // 'hello' read.next().value // 'h' ``` ---- 接收 `yield*` 的 `return` ``` function* foo() { yield 2; yield 3; return 'foo'; } function* bar() { yield 1; var v = yield* foo(); console.log('v: ' + v); yield 4; } var i = bar(); i.next(); // { value: 1, done: false } i.next(); // { value: 2, done: false } i.next(); // { value: 3, done: false } i.next(); // 'v: foo' // { value: 4, done: false } i.next(); // { value: undefined, done: true } ``` ---- ## 五. 當物件屬性是 generator ---- ```js const obj = { * myGeneratorMethod() { ··· } }; ``` ---- ## 中入淺出 Generator function 1. for…of 2. Generator.prototype.throw 3. Generator.prototype.return 4. yield* 5. 當物件屬性是 generator --- # 深入淺出 Generator function ---- ## 1. generator 的 this ---- gernerator 回傳的是 gernerator 實例 ```js function* g() {} g.prototype.hello = function () { return 'hi!'; }; const obj = g(); obj instanceof g; // true obj.hello(); // 'hi!' ``` ---- generator 返回的是遍歷器,不是 this ```js function* g() { this.a = 11; } let obj = g(); obj.a; // undefined ``` ---- 不能使用 new ```js function* F() { yield this.x = 2; yield this.y = 3; } new F() // TypeError: F is not a constructor ``` ---- ## 2. generator 的應用 1. 以同步化的方式撰寫異步操作 2. 控制流管理 3. 部署 iterator 接口 4. 作為數據結構
{"metaMigratedAt":"2023-06-14T11:46:37.591Z","metaMigratedFrom":"Content","title":"ES6: Generator function","breaks":true,"contributors":"[]"}
    1142 views