JavaScript >> Javascript 文檔 >  >> JavaScript

ES6 迭代器和生成器

在編寫代碼時,迭代器和生成器通常是次要的想法,但如果您可以花幾分鐘時間考慮如何使用它們來簡化代碼,它們將為您節省大量調試和復雜性。借助新的 ES6 迭代器和生成器,JavaScript 獲得了與 Java 的 Iterable 類似的功能,允許我們自定義對象的迭代。

例如,如果您有一個 Graph 對象,您可以輕鬆地使用生成器來遍歷節點或邊。通過將遍歷邏輯放在它所屬的 Graph 對像中,這使得代碼更加簡潔。這種邏輯分離是一種很好的做法,迭代器/生成器使遵循這些最佳做法變得更加容易。

ES6 迭代器和生成器

迭代器

使用迭代器,您可以創建一種使用 for...of 進行迭代的方法 為您的自定義對象構造。而不是使用 for...in ,它只是遍歷對象的所有屬性,使用 for...of 讓我們可以創建一個更加自定義和結構化的迭代器,我們可以在其中選擇每次迭代要返回的值。

在引擎蓋下,for...of 實際上是使用 Symbol.iterator .召回符號是 JavaScript ES6 中的一個新特性。 Symbol.iterator 是專門用於訪問對象的內部迭代器的特殊用途符號。因此,您可以使用它來檢索迭代數組對象的函數,如下所示:

var nums = [6, 7, 8];
var iterator = nums[Symbol.iterator]();
iterator.next();				// Returns { value: 6, done: false }
iterator.next();				// Returns { value: 7, done: false }
iterator.next();				// Returns { value: 8, done: false }
iterator.next();				// Returns { value: undefined, done: true }

當您使用 for...of 構造,這實際上是在下面使用的。注意每個後續值是如何返回的,還有一個指示符告訴您是否處於 絕大多數情況下您不需要使用 next() 像這樣手動操作,但如果您有需要更複雜循環的用例,則可以選擇。

您可以使用 Symbol.iterator 為對象定義專門的迭代。因此,假設您有自己的對象,它是句子的包裝器,Sentence .

function Sentence(str) {
    this._str = str;
}

為了定義我們如何迭代 Sentence 對象的內部,我們提供了一個原型迭代器函數:

Sentence.prototype[Symbol.iterator] = function() {
    var re = /\S+/g;
    var str = this._str;

    return {
        next: function() {
            var match = re.exec(str);
            if (match) {
                return {value: match[0], done: false};
            }
            return {value: undefined, done: true};
        }
    }
};

現在,使用我們剛剛在上面創建的迭代器(包含一個只匹配單詞的正則表達式字符串),我們可以輕鬆地迭代我們提供的任何句子的單詞:

var s = new Sentence('Good day, kind sir.');

for (var w of s) {
    console.log(w);
}

// Prints:
// Good
// day,
// kind
// sir.
發電機

ES6 生成器通過使用特殊語法構建在迭代器提供的內容之上,以便更輕鬆地創建迭代函數。生成器使用 function* 定義 關鍵詞。在 function* 內 ,您可以使用 yield 重複返回值 . yield 關鍵字在生成器函數中用於暫停執行並返回一個值。它可以被認為是 return 的基於生成器的版本 關鍵詞。在下一次迭代中,執行將在 yield 的最後一點恢復 被使用了。

function* myGenerator() {
    yield 'foo';
    yield 'bar';
    yield 'baz';
}

myGenerator.next();		// Returns {value: 'foo', done: false}
myGenerator.next();		// Returns {value: 'bar', done: false}
myGenerator.next();		// Returns {value: 'baz', done: false}
myGenerator.next();		// Returns {value: undefined, done: true}

或者,您可以使用 for...of 構造:

for (var n of myGenerator()) {
    console.log(n);
}

// Prints
// foo
// bar
// baz

免費電子書:Git Essentials

查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!

在這種情況下,我們可以看到生成器隨後負責返回 {value: val, done: bool} 為您提供的對象,所有這些都在 for...of 的後台處理 .

那麼我們如何使用生成器來發揮我們的優勢呢?回到我們之前的例子,我們可以簡化 Sentence 迭代到以下代碼:

Sentence.prototype[Symbol.iterator] = function*() {
    var re = /\S+/g;
    var str = this._str;
    var match;
    while (match = re.exec(str)) {
        yield match[0];
    }
};

請注意迭代器(現在是生成器)函數比以前的版本要小得多。我們不再需要返回帶有 next 的對象 函數,我們不再需要處理返回 {value: val, done: bool} 目的。雖然在此示例中這些節省可能看起來很少,但隨著您的生成器變得越來越複雜,它的用處將很容易實現。

優勢

正如 Jake Archibald 所指出的,這些生成器的一些優點是:

  • 懶惰 :這些值不會提前計算,所以如果你直到最後不迭代,你就不會浪費時間計算未使用的值。

  • 無限 :由於沒有提前計算值,因此您可以返回無限組的值。只要確保你在某個時候跳出循環。

  • 字符串迭代 :感謝Symbol.iterator , String 現在有自己的迭代器,可以更輕鬆地循環字符。遍歷字符串的字符符號可能會很痛苦。這在 JavaScript ES5 支持 unicode 的情況下特別有用。

    for (var symbol of string) {
    console.log(symbol);
    }

結論

雖然迭代器和生成器並不是很大的附加功能,但它們確實有助於清理代碼並使其保持井井有條。將迭代邏輯與其所屬的對象保持一致是一種很好的做法,這似乎是 ES6 特性的重點。該標準似乎正在朝著 Java 的結構化能力和設計友好性邁進,同時仍保持動態語言的開發速度。

你如何看待 ES6 的新特性?迭代器和生成器有哪些有趣的用例?請在評論中告訴我們!

感謝 Jake Archibald 的精彩文章,詳細介紹了迭代器和生成器在 ES6 中的工作原理。


上一篇
下一篇
Tutorial JavaScript 教程
  1. Javascript 中的行尾

  2. 面向您和您的團隊的 Angular 課程,終極課程的回顧

  3. 哈剋星期五的東西 #22.05.2020

  4. javascript:幕後

  5. Jade textarea中的長文本塊?

  6. 想學習 Web 開發並喜歡 YouTube 視頻嗎?讀這個!

  7. 登錄表單

  1. 使用 Alpine.js 構建模塊化應用程序

  2. 發現 Vue 3 的新特性

  3. 什麼是 React Native?混合移動應用的興起

  4. 我製作了一個 192 字節壓縮的 Node.js 顏色庫(+ 代碼解釋!)

  5. 點擊計數器 Bootstrap 輪播按鈕

  6. TDD 與 BDD

  7. TypeScript 和 ECMAScript 模塊

  1. 天才之路:初學者#6

  2. 為什麼我離開 App Engine 轉而選擇 Cloud Run

  3. 在 Angular 中探索 HttpClientModule

  4. 為什麼我們停止使用 npm start 來運行我們的區塊鏈核心子進程