學習 ECMAScript/JavaScript 6 - Generator
Generator 是 ECMAScript/JavaScript 6 新增的一項頗為有趣的語法功能。它的關鍵字是 yield 。
在上篇 介紹 for-of 與迭代器 時,我提到設計一件具有迭代能力的個體或類別時,需要添加額外資料以保存現行狀態。而 Generator 就是為了簡化這項設計工作而導入的新功能。
我在 介紹 for-of 與迭代器 一文最後往 o 加了兩個方法,把它變成了可以套用 for-of 的 iterator (迭代器)。在此我用 generator 改寫,可簡化為下列程式碼:
上述範例有新朋友,就是 function* / yield
。 ECMAScript/JavaScript 不想創造新的關鍵字,所以假借 function 為字眼,再加上一個 *
偏旁,造出 function*
表示 Generator 。而 generator 也不能用 return 返回,要用 yield 跳出。因為對 generator 而言,它只是暫時讓出(yield)執行權利給外部,並不是完工返回。
瞧瞧改寫的範例改變了什麼。[Symbol.iterator]()
和 next()
用 generator 一次搞定。原來為了保存現行狀態而由我添加 _iter 和 _current 也不用自己處理了。
簡而言之,上列範例告訴我們, ECMAScript/JavaScript 中的 Generator 就是一個在跳出執行工作前會保存現行狀態的程式區塊。當使用者再次調用這個程式區塊時,它便會根據上次保存的資訊恢復狀態,再繼續執行下一步。正式說法則是 Generator 就是定義一個具有 [Symbol.iterator]()
和 next()
方法的迭代器。它隱藏了 [Symbol.iterator]()
和恢復狀態的工作,讓設計者專注在 next()
該做的事。
前面的例子可能跳得有點快。再來一個範例,我用一般的函數敘述表達 Generator 的工作概念。我定義了一個函數 hello()
,希望第一次執行時給我 ‘hello’ 、第二次執行給我 ‘world’ 。所以它本身必須知道它是第幾次被調用。我配置了一個狀態保存區 state 給它,這讓它可以記憶現在它執行到第幾步了。
對了,雖然 generator 內只寫 yield value
,但調用者實際上是調用 next()
方法,所以 hello()
函數也模仿這一動作回傳 done/value 。當它沒有下一個步驟時,它就會回傳 {'done':true, 'value':undefined}
。
同樣的事,由 Generator 來做就可以簡化成:
因為 Generator 是定義一個迭代器,所以你調用 generator 時,它會回傳一個迭代器給你。你接著只需要調用這個迭代器的 next()
方法。
當你在 for-of
中使用 generator 時,for-of
會檢查 ‘done’ 之值。在這以外的使用場合,你得要記得檢查 next()
方法回傳的 ‘done’ 內容。
Generator 具有相當強大的應用威力,不過它使用在迴圈以外的場合時有些違反過往的編程習慣。先從設計可走訪的資料集合開始練習吧。
相關文章
- 更多關於 Generator 的事,可進一步閱讀 ES6 In Depth: Generators 。
- 石頭閒語: ECMAScript/JavaScript 6 - Template strings
- 石頭閒語: ECMAScript/JavaScript 6 - Symbol
- 石頭閒語: ECMAScript/JavaScript 6 - for-of 與 iterator。
- 石頭閒語: ECMAScript/JavaScript 6 - Generator
- 石頭閒語: ECMAScript/JavaScript 6 - 新函數語法 - Arrow functions, Rest and Spread parameters, Default value
- 石頭閒語: ECMAScript/JavaScript 6 - Destructuring
- 石頭閒語: ECMAScript/JavaScript 6 - var, let 和 const
- 石頭閒語: ECMAScript/JavaScript 6 - Proxy 和 Reflect
- 石頭閒語: ECMAScript/JavaScript 6 - Class
- 石頭閒語: ECMAScript/JavaScript 6 - 語法補遺
- 石頭閒語: ECMAScript/JavaScript 6 - Promise