Javascript 生成器(Generator)

做者:Alan Storm

翻譯:瘋狂的技術宅javascript

原文:https://alanstorm.com/javascr...前端

未經容許嚴禁轉載java

什麼是生成器?

生成器是在函數內部運行的一些代碼node

  1. 返回值後,它會自行暫停,而且——
  2. 調用程序能夠要求取消暫停並返回另外一個值

這種「返回」不是傳統的從函數 return。因此它被賦予了一個特殊的名稱——yield程序員

生成器語法因語言而異。 Javascript 的生成器語法相似於 PHP,可是區別也很大,若是你但願它們的做用相同,那麼最終你會感到很是困惑。面試

在 javascript 中,若是想要使用生成器,則須要:json

  1. 定義特殊的生成器函數
  2. 調用該函數建立一個生成器對象
  3. 在循環中使用該生成器對象,或直接調用其 next 方法

咱們如下面這個簡單的程序作爲起點,並執行如下每一個步驟:segmentfault

// File: sample-program.js
function *createGenerator() {
  for(let i=0;i<20;i++) {
    yield i
  }
}

const generator = createGenerator()

console.log(generator.next())
console.log(generator.next())

若是運行這段代碼,則會獲得如下輸出:bash

$ node sample-program.js

{ value: 0, done: false }
{ value: 1, done: false }

下面我來解釋該程序是如何工做的。服務器

生成器函數

首先,代碼中存在生成器函數的定義:

function* createGenerator() {
  for(let i=0;i<20;i++) {
    yield i
  }
}

function 後面的 * 告訴 javascript 這是一個生成器函數。如下寫法都是生成器函數的有效定義。

function*createGenerator
function* createGenerator
function *createGenerator

*不是函數名的一部分。而是 function* 符號定義了生成器。

調用生成器函數

定義了生成器函數後,咱們將其命名爲其餘名稱的函數。

// 注意:當調用時,沒有 *。 * 不是函數名稱的一部分
// `function *` 是用於定義生成器函數的符號
const generator = createGenerator()

可是要記住:createGenerator 函數沒有返回值。這是由於生成器函數沒有傳統的返回值。相反,當你直接調用生成器函數時,它老是返回實例化的 Generator 對象。

這個生成器對象具備一個 next 方法。調用 next 將在生成器函數內部運行代碼。

function* createGenerator() {
    for(let i=0;i<20;i++) {
        yield i
    }
}

這很重要,足以再次調用它。直接調用生成器函數不會在生成器函數中運行任何代碼。而是建立一個生成器對象。它在生成器對象上調用 next,從而調用生成器函數中的代碼。

首次在生成器對象上調用 next 時,內部代碼將會一直運行,直到出現 yield 語句。一旦執行到 yield,javascript 將會暫停該代碼的執行,而 next 將返回(即給你,或yield)一個對象,該對象包含 yield 行中的值。

當你第二次(或第三次、第四次甚至更屢次)再調用 next 時,代碼將會取消暫停並繼續運行(在上次調用時中斷的地方)。變量(例如本例中的 i )將會保持它的值。當代碼到達另外一個 yield 語句時,該函數會再次暫停,並返回一個包含 yield 值的對象。

這就是爲何咱們要調用兩次 next

console.log(generator.next())
console.log(generator.next())

會獲得如下輸出:

{ value: 0, done: false }
{ value: 1, done: false }

生成器函數中的代碼執行完畢後,未來對 next 的任何調用都會返回一個對象,該對象的值爲 undefineddone 設置爲 true

{ value: undefined, done: true }

生成器和循環

雖然能夠在生成器對象上手動調用 next,但咱們主要是要在循環中使用。看一下這個稍做修改的程序。

// File: sample-program.js
@highlightsyntax@jscript
function *createGenerator() {
  for(let i=0;i<5;i++) {
    yield i
  }
}

const generator = createGenerator()
for(const value of generator) {
  console.log(value)
}

當在 for...of 循環中使用生成器對象時,每次循環都會在生成器對象上調用 next,並用產生的值填充變量(上面的 value)。運行該程序將會輸出如下內容:

$ node sample-program.js
0
1
2
3
4

在下一篇文章中,咱們將更深刻地探討 for ... of 循環,並探索怎樣爲 javascript 提供一種內置方法來循環 javascript 中的任何對象。

173382ede7319973.gif


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索