Iterator遍歷器
Iterator(遍歷器)的概念
JavaScript原有的表示“集合”的資料結構,主要是陣列(Array)和物件(Object),ES6又添加了Map和Set。這樣就有了四種資料集合,使用者還可以組合使用它們,定義自己的資料結構,比如陣列的成員是Map,Map的成員是物件。這樣就需要一種統一的介面機制,來處理所有不同的資料結構。
遍歷器(Iterator)就是這樣一種機制。它是一種介面,為各種不同的資料結構提供統一的訪問機制。任何資料結構只要部署Iterator介面,就可以完成遍歷操作(即依次處理該資料結構的所有成員)。
Iterator的作用有三個:一是為各種資料結構,提供一個統一的、簡便的訪問介面;二是使得資料結構的成員能夠按某種次序排列;三是ES6創造了一種新的遍歷命令for...of
for...of
消費。
Iterator的遍歷過程是這樣的。
(1)建立一個指標物件,指向當前資料結構的起始位置。也就是說,遍歷器物件本質上,就是一個指標物件。
(2)第一次呼叫指標物件的next
方法,可以將指標指向資料結構的第一個成員。
(3)第二次呼叫指標物件的next
方法,指標就指向資料結構的第二個成員。
(4)不斷呼叫指標物件的next
方法,直到它指向資料結構的結束位置。
每一次呼叫next
方法,都會返回資料結構的當前成員的資訊。具體來說,就是返回一個包含value
和done
兩個屬性的物件。其中,value
屬性是當前成員的值,done
屬性是一個布林值,表示遍歷是否結束。
我們應該如何理解這種遍歷器的機制?我們可以聯想到自己的生活,比如我們的冰箱、洗衣機、電視雖然功能各自不同,但是有一個“介面”是統一的,那就是電源線, 不是兩頭的就是三頭的
iterator是一種介面機制,使用或者設計的時候必須要遵循這種機制
Iterator的模擬封裝
function makeIterator(array) { // 起始下標 var nextIndex = 0; return { // 封裝的next方法 next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; } // 註冊iterator var it = makeIterator(['1', '2','3']); console.log(it.next()); console.log(it.next()); console.log(it.next()); console.log(it.next());
上圖中的{value:**,done:false}這種格式的返回就是所謂的iterator介面的規則,value表示當前這次遍歷出來的值,done表示遍歷是否結束。false為未結束,true為已結束
Iterator的遍歷過程是這樣的:
1>建立一個指標物件,指向當前資料結構的起始位置。也就是說,遍歷器物件本質上,就是一個指標物件。
2>第一次呼叫指標物件的next方法,可以將指標指向資料結構的第一個成員。
3>第二次呼叫指標物件的next方法,指標就指向資料結構的第二個成員。
4>不斷呼叫指標物件的next方法,直到它指向資料結構的結束位置。
資料結構的預設Iterator介面
Iterator介面的目的,就是為所有資料結構,提供了一種統一的訪問機制,即for...of
迴圈。當使用for...of
迴圈遍歷某種資料結構時,該迴圈會自動去尋找Iterator介面。
一種資料結構只要部署了Iterator介面,我們就稱這種資料結構是”可遍歷的“(iterable)。
ES6規定,預設的Iterator介面部署在資料結構的Symbol.iterator屬性,或者說,一個數據結構只要具有Symbol.iterator屬性,就可以認為是“可遍歷的”(iterable)
比如陣列就是擁有遍歷器能力的
如何使用遍歷器?
以陣列為例
<script> var arr = [1,2,3,4,5]; // 註冊iterator var it = arr[Symbol.iterator](); console.log(it.next()); console.log(it.next()); console.log(it.next()); console.log(it.next()); console.log(it.next()); console.log(it.next()); </script>
在ES6中,有三類資料結構原生具備Iterator介面:陣列、某些類似陣列的物件、String、Set和Map結構
for...of迴圈
一個數據結構只要部署了Symbol.iterator屬性,就被視為具有iterator介面,就可以用for...of迴圈遍歷它的成員
比如陣列
<script> var arr = [1,2,3,4,5]; for(let item of arr){ console.log(item); } </script>
arguments物件
<script> function arr() { for (let x of arguments) { console.log(x); } } arr(1,2,3,4,5); </script>
除了for...of迴圈以外,擴充套件運算子(...)、解構賦值和Array.from方法內部呼叫的,都是遍歷器介面