快速了解ES6的迭代器

JavaScript迭代器.png

ECMAScript 6 規(guī)范新增的迭代器是一種新的遍歷機制,能夠更清晰、高效、方便地實現(xiàn)迭代。所有通過迭代器訪問的結構都實現(xiàn)了 Iterator 接口,且能夠在 for...of 循環(huán)中應用。

可迭代協(xié)議

可迭代協(xié)議指的是實現(xiàn) Iterable 接口并同時支持迭代的自我識別能力和創(chuàng)建實現(xiàn) Iterator 接口的對象的能力。任何實現(xiàn) Iterable 接口的對象都有一個 Symbol.iterator 屬性,這個屬性引用默認迭代器。默認迭代器是一個函數(shù),調(diào)用之后會產(chǎn)生一個實現(xiàn) Iterator 接口的對象。內(nèi)置的可迭代對象有 StringArray、MapSet 等等。

下面給出幾個例子,可以檢查是否存在默認迭代器屬性:

let obj = {};
let num = 3;
// Object 和 Number 都沒有實現(xiàn)迭代器函數(shù)
console.log(obj[Symbol.iterator]);    // undefined
console.log(num[Symbol.iterator]);    // undefined

let arr = ["小明", "小李"];
let set = new Set().add('小明').add('小李');
// Array 和 Set 都實現(xiàn)了迭代器函數(shù)
console.log(arr[Symbol.iterator]);    // [Function: values]
console.log(set[Symbol.iterator]);    // [Function: values]

// 下面獲取迭代器
console.log(arr[Symbol.iterator]());    // Object [Array Iterator] {}
console.log(set[Symbol.iterator]());    // [Set Iterator] { '小明', '小李' }

實際上,實現(xiàn)可迭代協(xié)議的迭代對象都可以在如下場景使用:

  • for-of 循環(huán)
  • 數(shù)組解構
  • 擴展操作符
  • Array.from()
  • 集合與映射
  • Promise 組成的可迭代對象
  • yield* 操作符
let arr = ["小玲", "小霞", "小星", "小民"];
// for-of循環(huán)
for (let v of arr) {
    console.log(v);
}
// 數(shù)組解構
let [a1, a2, a3, a4] = arr;
console.log(a1, a2, a3, a4);    // 小玲 小霞 小星 小民
// 擴展操作符
let arr2 = [...arr];
console.log(arr2);    // [ '小玲', '小霞', '小星', '小民' ]
// Array.from()
let arr3 = Array.from(arr);
console.log(arr3);    // [ '小玲', '小霞', '小星', '小民' ]

如果對象原型鏈上的父類實現(xiàn)了 Iterable 接口,那這個對象也會實現(xiàn) Iterable 接口:

如果對象原型鏈上的父類實現(xiàn)了 Iterable 接口,那這個對象也就實現(xiàn)了這個接口:

class List extends Array {}
let list = new List("小玲", "小霞", "小星", "小民");
for (let v of list1) {
    console.log(v);
}
// 小玲
// 小霞
// 小星
// 小民

迭代器協(xié)議

迭代器協(xié)議定義了產(chǎn)生一些列值的標準方法。而對象只有實現(xiàn)了 next() 方法才能成為迭代器。對象使用 next() 遍歷數(shù)據(jù)時,每次成功都會返回一個 IteratorResult 對象,其中包含迭代返回的下一個值;所有的值都迭代完后,會返回一個默認返回值;若不調(diào)用 next(),則無法知道迭代器的當前位置。

next() 方法返回的 IteratorResult 包含兩個屬性:

  • done:布爾值。表示是否還可以調(diào)用 next() 獲取下一個值。 迭代器遍歷完畢會返回 true;否則返回 false。
  • value:迭代器返回的值。donetrue 可省略或 undefined。

可以通過以下簡單的數(shù)組來演示:

let arr = ["小明", "小李"];
// 獲取迭代器
let iter = arr[Symbol.iterator]();
// 執(zhí)行迭代
console.log(iter.next());    // { value: '小明', done: false }
console.log(iter.next());    // { value: '小李', done: false }
console.log(iter.next());    // { value: undefined, done: true }
console.log(iter.next());    // { value: undefined, done: true }

在迭代期間修改了迭代對象,會反映在迭代對象上,如下所示:

let arr = ["小明", "小李"];
// 獲取迭代器
let iter = arr[Symbol.iterator]();
console.log(iter.next());    // { value: '小明', done: false }
console.log(iter.next());    // { value: '小李', done: false }
arr.splice(2, 0, "小虎");    
console.log(iter.next());    // { value: '小虎', done: false }
console.log(iter.next());    // { value: undefined, done: true }
console.log(iter.next());    // { value: undefined, done: true }

這是因為使用 next() 獲取對象只是使用游標來記錄歷程。

<small>注意:迭代器維護著一個指向可迭代對象的引用,因此迭代器會阻止垃圾回收程序回收可迭代對象。</small>

自定義迭代器

因為每個迭代器也實現(xiàn)了Iterable 接口,所以它們可以用在任何期待可迭代對象的地方,比如for-of 循環(huán):

每個實現(xiàn)了 Iterable 接口的迭代器都可以用在任何可迭代對象的地方,如 for-of 循環(huán)。下面自定義一個實現(xiàn)迭代器的類:

class List {
    constructor() {
        this.index = 0;
        this.data = arguments;
    }

    [Symbol.iterator]() {
        return {
            next: () => {
                if (this.index < this.data.length) {
                    return { value: this.data[this.index++], done: false};
                }
                this.index = 0;
                return {done: true, value: undefined};
            }
        }
    }
}

let list = new List("小玲", "小霞", "小星", "小民");
let iter = list[Symbol.iterator]();
console.log(iter.next());    // { value: '小玲', done: false }
console.log(iter.next());    // { value: '小霞', done: false }
console.log(iter.next());    // { value: '小星', done: false }
console.log(iter.next());    // { value: '小民', done: false }
console.log(iter.next());    // { done: true, value: undefined }

任何實現(xiàn) Iterable 接口的數(shù)據(jù)結構都可以實現(xiàn) Iterator 接口的結構 “消費”。

提前終止迭代器

當使用 for-of 循環(huán)迭代器時,如果不想迭代下去,可以通過 breakcontinue、returnthrow 提前退出。

for (let v of list) {
    if (v === '小星') {
        console.log("提前退出");
        break;
    }
    console.log(v);    
}
// 小玲
// 小霞
// 提前退出

總結

迭代器是 ES6 新增的重要功能,提供了一個可以由任意對象實現(xiàn)的接口,并連續(xù)返回迭代對象中的每個值。任何實現(xiàn) Iterable 接口的對象都有一個 Symbol.iterator 屬性,這個屬性引用默認迭代器。當一個對象中存在 Symbol.iterator 時,該對象就會被認為是可迭代對象。

更多內(nèi)容請關注公眾號「海人為記

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 簡單介紹下 ES6 規(guī)范里面迭代器(Iterator)相關的概念。最近為啥會看到迭代器,是因為看了 fetch 相...
    唯泥Bernie閱讀 352評論 0 0
  • 迭代器 迭代器是被設計專用于迭代的對象,帶有特定接口。所有的迭代器對象都擁有next()方法,會返回一個結果對象。...
    風間靈佑閱讀 194評論 0 0
  • 什么是迭代器? 迭代器是被設計專用于迭代的對象,帶有特定接口。所有的迭代器對象都擁有 next() 方法,會返回一...
    27億光年中的小小塵埃閱讀 272評論 0 0
  • 前言 該部分為書籍 深入理解ES6 第八章(迭代器與生成器)筆記 循環(huán)的問題 雖然這個循環(huán)非常直觀, 然而當它被嵌...
    歲月靜好_不負此生閱讀 353評論 0 0
  • 迭代的英文是 “iteration”,源自拉丁文 “itero”,是“重復”或“再來”的意思。在軟件開發(fā)領域,“迭...
    越前君閱讀 1,280評論 0 3

友情鏈接更多精彩內(nèi)容