1. 程式人生 > >從JavaScript學習設計模式(Iterator)

從JavaScript學習設計模式(Iterator)

  ES6增加了Map,Set資料結構而且還實現了迭代器機制(Iterator),這是多麼令人興奮的事情。

迭代器(Iterator)模式,又叫做遊標(Cursor)模式。GOF給出的定義為:提供一種方法訪問一個容器(container)物件中各個元素,而又不需暴露該物件的內部細節。 從定義可見,迭代器模式是為容器而生。很明顯,對容器物件的訪問必然涉及到遍歷演算法。你可以一股腦的將遍歷方法塞到容器物件中去;或者根本不去提供什麼遍歷演算法,讓使用容器的人自己去實現去吧。這兩種情況好像都能夠解決問題。(取自百度百科,發現百度的名詞解釋比維基棒 :P )

即Iterator是為了遍歷容器(set , map , array,object)而提供的介面

下面我會從幾個方面來闡述JavaScript的迭代器:
0x00 Iterator實現原理及使用
0x01 對JavaScript的迴圈方法進行彙總

0x00 Iterator原理及使用姿勢

實際上遍歷的原理大家都能想得到。

抽象資料型別(Abstract Data Type ADT)是一個數據模型以及包含對資料的操作,定義並實現了抽象資料模型就可以像使用基本資料型別那樣。

資料結構是實現抽象資料型別的演算法。

首先建立我們需要一個類似指標☞的物件(下面稱為指標物件),記下當前抽象資料型別起點(陣列,物件等可遍歷資料型別,阮老師這裡寫的是資料結構,個人認為ADT更合適),而且返回格式為 { value : “XXX” , done : false } ,當遍歷結束則返回 {value : undefined , done : true} 。

最重要的是為這個指標物件新增next( )方法(有沒覺得很熟悉,資料結構課程我們經常遇到),當我們第一次呼叫next( )指標就指向ADT第一個成員。相應的,第二次呼叫就指向第二個成員。

然後不斷地呼叫next( ) ,就一直遍歷下去直到指向ADT結束的位置。

還有很重要的一點(“敲黑板” ),ES6規定只有具有Symbol.iterator屬性的ADT才具備可遍歷性,而且使用Iterator之前需要呼叫Symbol.iterator方法(攤手.jpg),其實知道了原理我們也能寫個Iterator介面玩玩。
陣列,類陣列物件,Set和Map內建Iterator介面,使用方法如下

let arr = [ “1” , “2” , “3”]
let it = arr[Symbol.iterator] ( )
it.next( ) // { value: “1” , done: false}
it.next( ) // { value: “2” , done: false}
it.next( ) // { value: “3” ,done: false}
it.next( ) // { value: undefined , done: true}

ES6引用了for … of ,只要具有Symbol.iterator屬性就可以用for…of 來遍歷,即for…of 迴圈內部呼叫的是Iterator介面方法。

let arr = [“1”,”2”,”3”]
for (let v of arr){
     console.log(v)
}

let s = new Set([“1”,”2”,”3”])
for (let a of s){
     console.log(a)
}

另外解構賦值,擴充套件運算子也是預設呼叫Iterator介面

既然有引入了for…of,而且許多ADT預設呼叫Iterator介面,而且使用 it.next( )方式來遍歷還不如 for…of來的簡單,暴力,這樣看起來it.next( )遍歷方式貌似有點弱了。

顯然這是不對的。

(華麗的分割線)
ES6提供了Generator函式來解決非同步程式設計,當Generator遇上Iterator產生的化學反應——狀態機。(Generator需要較長的篇幅來講解,會專門寫篇關於非同步程式設計部落格,這裡就不深究了)

0x01 對JavaScript所有迭代的方法進行彙總

for迴圈是最常見的一種寫法,大家都很熟悉了。

for-in是用來遍歷的是物件的屬性(可列舉屬性),而在JavaScript中Array可以看成特殊的物件,因此使用for-in遍歷陣列得到的是陣列的索引。在使用for-in的時候,會遍歷原型鏈,所以在一些場景下for的效能高於for-in。

因為for-in會遍歷原型鏈,而且forEach()不支援break和return,所以ES6新增了for-of ,解決了這些問題,而且ES6新增的set,map等資料結構只要內建有Iterator的通通都可以使用 “for-of” 來遍歷資料。

最後,以下是ES5為陣列定義了5個迭代方法。

  • every
  • filter
  • forEach
  • map
  • some
  • every( )

    對陣列每一項執行回撥函式,如果該函式對每一項都返回true則返回true。

    這裡寫圖片描述

    some( ) # 跟every( )有些差別,但使用場景差不多

    對陣列每一項執行回撥函式,如果該函式對任一項返回true則返回true。

    filter( ) # 起到過濾功能

    對陣列每一項執行回撥函式,返回該函式會返回true的項組成的陣列

    這裡寫圖片描述

    forEach( )

    對陣列每一項執行回撥函式,沒有返回值

    (”敲黑板”,考試重點)☞ forEach迴圈中,break或return不能跳出迴圈

    這裡寫圖片描述

    map( )

    對陣列每一項執行回撥函式,返回所有執行結果組成的陣列。

    這裡寫圖片描述

     
      本文參考《JavaScript高階程式設計》以及阮一峰老師的《ES6標準入門》