Generator 是 ES6 提出的一種異步編程的解決辦法,它與傳統的函數徹底不一樣,本章從基礎概念和基本用法進行講解和解析。在此以前也是對 Generator 函數雲裏霧裏,因此經過這次學習,但願能對 Generator 有更深的理解和認識。前端
Generator 中文的意思是'生成器',阮一峯:ECMAScript 6 入門中對 Generator 解釋是: Generator 函數有多種理解角度。語法上,首先能夠把它理解成,Generator 函數是一個狀態機,封裝了多個內部狀態。git
執行 Generator 函數會返回一個遍歷器對象,也就是說,Generator 函數除了狀態機,仍是一個遍歷器對象生成函數。返回的遍歷器對象,能夠依次遍歷 Generator 函數內部的每個狀態。 Generator 有兩個特色: 第一個是在定義時,要在 function 關鍵字和函數名中加一個星號,第二個就是在函數體中運用 yeild 表達式表示不一樣的狀態。es6
function* foo() {
yield "a"; yield "b"; } let f = foo(); console.log(f); 複製代碼
和普通函數不一樣的是,當運行這個函數時,返回不是這個函數的結果,而是一個遍歷器對象,或者能夠說是一個含有內部狀態指針的對象。 若是想輸出值得話,要用 next 方法來進行輸出。next 方法就是向下移動指針,即每次調用 next 方法,就是從函數頭部或者從上一次 yield 表達式移動到下一次 yield 表達式(或者 return 爲止)。github
function* foo() {
yield "a"; yield "b"; } let f = foo(); f.next(); // {value: "a", done: false} f.next(); // {value: "b", done: false} f.next(); // {value: undefined, done: true} 複製代碼
上述能夠看出,調用 next 時輸出的是一個對象,即 value 值表明 yield 後面的結果,done 表明遍歷尚未結束,當遍歷結束時,value 值都爲 undefined,done 都爲 true。編程
yield 有個懶惰的特性,即 yield 後面的表達式,若是不調用 next 方法,是不會執行的。markdown
function* foo() {
yield 1 + 1; } foo().next(); // 2 複製代碼
只有當 next 指針移動到該 yield 的時候,纔會執行後面的表達式。 yield 和 return 是有不一樣之處的,在 Generator 函數中,能夠定義多個 yield 表達式,可是 return 只能定義一個,而且在 yield 中遍歷尚未完成,但在遇到 return 時,遍歷就終止了。異步
function* foo() {
yield "a"; yield "b"; return "c"; } let f = foo(); f.next(); // {value: "a", done: false} f.next(); // {value: "b", done: false} f.next(); // {value: "c", done: true} f.next(); // {value: undefined, done: true} 複製代碼
當遇到 return 時,遍歷結束 done 爲 true,value 值爲 return 後的結果,在此以後的 next 的結果都爲{value: undefined, done: true}。 若是在 Generator 函數中沒有 yield 表達式:ide
function* foo() {
console.log("a"); } let f = foo(); f.next(); 複製代碼
foo()返回的依舊是一個含有內部狀態指針的對象,只有當 next 方法執行時該函數纔會執行。 當 yield 和其餘表達式融合時,若是 yield 表達式在左邊,要將 yield 表達式用圓括號包裹,不然就會報語法錯誤。異步編程
function* foo() {
console.log('a'+ yield 'b'); // Uncaught SyntaxError: Unexpected identifier } function* foo() { console.log('a'+ (yield 'b')); // {value: "b", done: false} } let f = foo(); f.next(); 複製代碼
當用做函數參數或放在賦值表達式的右邊,能夠不加括號。函數
function* demo() {
foo(yield "a", yield "b"); // OK let input = yield; // OK } 複製代碼
yield 是沒有返回值的,它的返回值是 undefined,咱們能夠經過 next 方法將參數傳遞給 yield,此參數將會爲 yield 的返回值。
function* f() {
for (var i = 0; true; i++) { var reset = yield i; if (reset) { i = -1; } } } var g = f(); g.next(); // { value: 0, done: false } g.next(); // { value: 1, done: false } g.next(true); // { value: 0, done: false } 複製代碼
上面代碼先定義了一個能夠無限運行的 Generator 函數 f,若是 next 方法沒有參數,每次運行到 yield 表達式,變量 reset 的值老是 undefined。當 next 方法帶一個參數 true 時,變量 reset 就被重置爲這個參數(即 true),所以 i 會等於-1,下一輪循環就會從-1 開始遞增。 不用 next 方法是否能夠輸出值呢?答案是能夠的,能夠用 for...of...方法遍歷 Generator 函數。
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...在 done 爲 ture 的時候就會終止執行,因此 return 後的 6 沒有輸出。
yield* 表達式是爲了解決在一個 Generator 函數中調用另外一個 Generator 函數所提供的方法。
function* foo() {
yield 1; yield 2; yield 3; yield* foo1(); } 等同於; function* foo() { yield 1; yield 2; yield 3; for (let v of foo1()) { yield v; } } 複製代碼
當 yield*後邊的 Generator 函數中沒有 return 時,做用就是 for...of...遍歷 Generator 函數,若是 Generator 函數中有 return 時,則獲取的是 return 值。
function* foo() {
yield 1; yield 2; yield 3; var value = yield* foo1(); console.log(value); } function* foo1() { yield 4; return 5; } let f = foo(); f.next(); // {value: 1, done: false} f.next(); // {value: 2, done: false} f.next(); // {value: 3, done: false} f.next(); // 5 {value: undefined, done: true} 複製代碼
其實 yield*後面只要是帶有 Iterator 接口的都會被遍歷。
function* foo() {
yield* [1, 2, 3, 4]; } let f = foo(); f.next(); // {value: 1, done: false} 複製代碼
再舉個例子:
function* foo() {
yield "a"; yield "b"; return "END"; } function* bar(func) { let result = yield* func(); console.log(result); } [...bar(foo)]; // END // ["a", "b"] 複製代碼
上述中 foo 是擁有 return 表達式的函數,因此 return 後的結果會‘賦值’給 yield*表達式的返回值,因此 result 是'END',而且拓展運算符默認調用 Iterator 接口,因此會先打印出 result,而後再執行 yield。
參考:
相關文章:
以爲還能夠的,麻煩走的時候能給點個贊,你們一塊兒學習和探討!
還能夠關注個人博客但願能給個人github上點個Start,小夥伴們必定會發現一個問題,個人全部用戶名幾乎都與番茄有關,由於我真的很喜歡吃番茄❤️!!!
想跟車不迷路的小夥還但願能夠關注公衆號 前端老番茄 或者掃一掃下面的二維碼👇👇👇。
我是一個編程界的小學生,您的鼓勵是我不斷前進的動力,😄但願能一塊兒加油前進。
本文使用 mdnice 排版