ES6之Iterator遍歷器

遍歷器(Iterator)是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只要部署 Iterator 接口,就能夠完成遍歷操做(即依次處理該數據結構的全部成員)。數組

其實iterator在之前是內置在JavaScript中,主要是Array和Object表示的集合數據結構使用。ES6新增了map和set數據結構,這樣就有了四種數據集合。這樣就須要一個統一接口機制來處理不一樣的數據結構。Iterator就是這個做用。bash

Iterator 的做用有三個:數據結構

爲各類數據結構,提供一個統一的、簡便的訪問接口;函數

使得數據結構的成員可以按某種次序排列;ui

ES6 創造了一種新的遍歷命令for...of循環,Iterator 接口主要供for...of消費。spa

Interator內部遍歷過程:prototype

建立一個指針對象,指向當前數據結構的起始位置。遍歷器對象本質上,就是一個指針對象。指針

第一次調用指針對象的next方法,能夠將指針指向數據結構的第一個成員。code

第二次調用指針對象的next方法,指針就指向數據結構的第二個成員。orm

不斷調用指針對象的next方法,直到它指向數據結構的結束位置。

每一次調用next方法,都會返回數據結構的當前成員的信息。就是返回一個包含value和done兩個屬性的對象。value屬性是當前成員的值,done屬性是一個布爾值,表示遍歷是否結束。

咱們說了,Iterator 接口的目的,就是爲全部數據結構,提供了一種統一的訪問機制,主要提供給ES6的for of使用。當咱們使用for of的時候會自動尋找Interator接口。一種數據結構只要部署了Iterator接口,咱們就稱之爲可遍歷的(iterable)。

ES6 規定,默認的 Iterator 接口部署在數據結構的Symbol.iterator屬性,或者說,一個數據結構只要具備Symbol.iterator屬性,就能夠認爲是「可遍歷的」(iterable)。

Symbol.iterator屬性自己是一個函數,就是當前數據結構默認的遍歷器生成函數。執行這個函數,就會返回一個遍歷器。屬性名Symbol.iterator,它是一個表達式,返回Symbol對象的iterator屬性,這是一個預約義好的、類型爲 Symbol 的特殊值,因此要放在方括號內。

ES6 的有些數據結構原生具有 Iterator 接口(好比數組),即不用任何處理,就能夠被for...of循環遍歷。緣由在於,這些數據結構原生部署了Symbol.iterator屬性,另一些數據結構沒有(好比對象)。凡是部署了Symbol.iterator屬性的數據結構,就稱爲部署了遍歷器接口。調用這個接口,就會返回一個遍歷器對象。

咱們給一個obj部署:

const obj = {  

  [Symbol.iterator] : function () {    

    return {      

      next: function () {         

       return {            

        value: 1,           

         done: true        

        };      

      }    

    };  

  },  

  a: 1};

console.log(obj[Symbol.iterator]().next());//{value: 1, done: true}
複製代碼

原生具有 Iterator 接口的數據結構以下。

Array

Map

Set

String

TypedArray

函數的 arguments 對象

NodeList 對象

咱們使用數組的Symbol.iterator屬性:

var arr = [1, 2];

var arrIter = arr[Symbol.iterator]();

console.log(arrIter.next());//{value: 1, done: false}

console.log(arrIter.next());//{value: 2, done: false}

console.log(arrIter.next());//{value: undefined, done: true}
複製代碼

對於原生部署 Iterator 接口的數據結構,不用本身寫遍歷器生成函數,for...of循環會自動遍歷它們。除此以外,其餘數據結構(主要是對象)的 Iterator 接口,都須要本身在Symbol.iterator屬性上面部署,這樣纔會被for...of循環遍歷。

要注意的是,部署了Symbol.iterator屬性的並不能直接用for of循環,想要使用for of循環還須要在Symbol.iterator屬性上部署遍歷器生成方法。這邊分享相似數組的對象調用數組的Symbol.iterator例子,其餘的能夠自行研究:

var iterable = {  

  0: 'a',  

  1: 'b',  

  2: 'c',  

  length: 3,  

  [Symbol.iterator]: Array.prototype[Symbol.iterator]

};

for (var item of iterable) {  

  console.log(item); // a b c

}
複製代碼

普通對象這樣使用是沒有效果的。

雖然遍歷器接口Iterator(就是Symbol.iterator)是給for of使用,可是其餘不少會默認調用Symbol.iterator方法:

解構賦值、擴展運算符、yield*、Array.form、Map()、Set()、WeakSet()、WeakMap()、Promise.all()、Promise.race()等。

字符串是一個類數組,原生具備Iterator接口:

var str = 'abc';

var strIter = str[Symbol.iterator]();

console.log(strIter.next());//{value: "a", done: false}

console.log(strIter.next());//{value: "b", done: false}

console.log(strIter.next());//{value: "c", done: false}

console.log(strIter.next());//{value: undefined, done: true}
複製代碼

遍歷器對象除了具備next方法,還能夠具備return方法和throw方法。若是你本身寫遍歷器對象生成函數,那麼next方法是必須部署的,return方法和throw方法是否部署是可選的。

return方法的使用場合是,若是for...of循環提早退出(一般是由於出錯,或者有break語句),就會調用return方法。若是一個對象在完成遍歷前,須要清理或釋放資源,就能夠部署return方法。throw方法主要是配合 Generator 函數使用

一個數據結構只要部署了Symbol.iterator屬性,就被視爲具備 iterator 接口,就能夠用for...of循環遍歷它的成員。也就是說,for...of循環內部調用的是數據結構的Symbol.iterator方法。

for...of循環可使用的範圍包括數組、Set 和 Map 結構、某些相似數組的對象(好比arguments對象、DOM NodeList 對象)、後文的 Generator 對象,以及字符串。

var str = 'abc';

for(var val of str){  

  console.log(val);

}
複製代碼

有了for of,不少遍歷的操做均可以使用,配合entries、keys、values,好比對象不能直接用for of遍歷,咱們能夠用keys方法把對象的鍵變成數組去遍歷。

相對於其餘遍歷方法,for of會有一些優點,最大的優點我以爲就是提供了遍歷全部數據的統一操做接口。

相關文章
相關標籤/搜索