【前端】【javascript】es6中的遍歷器接口Iterator

  很久沒發文章啦-。-爲了證實我還活着,我決定從筆記裏面抓一篇還算不亂比較像文章的發出來。。。
  這些筆記是我在學es6的時候斷斷續續記錄的,最近會一份一份整理陸陸續續發出來,順便也本身再看一遍。我學習es6的時候主要是閱讀的阮一峯大神的文章,有須要的能夠搜索來閱讀,很系統。
  
1.概念
   第一次看到這個概念是當年學C++的時候,STL庫中的迭代器。在es6中,Iterator也差很少是這個意思。
  在es6中,能表示「集合」概念的數據類型大體有四種。  
   Array,Object,Map,Set
 
  既然是集合,那遍歷即是一種基本需求。而Iterator就是爲了提供一種統一的接口機制。任何的數據結構,只要部署了Iterator接口,即可以使用相似的方式完成遍歷操做。
 
  固然,Iterator還有2個做用,它使數據結構的成員按某種次序排列,其次,es6有一種新的遍歷方式,前面也說過,for...of,而Iterator的主要做用,就是支持此操做。
 
  Iteartor的遍歷過程和C++語言同樣
  1)建立一個指向數據結構起始位置的指針。(起始位置不是第一個成員的位置,起始位置使一個單獨的標誌位。)
  2)當調用next()方法,指針就向後移動一個位置,並返回當前位置上的成員,直到指針指向數據結構的結束位置爲止。
 
  第二步中,js語言返回的的成員信息是兩個,value和done,value不用介紹,done是一個表示遍歷是否結束的布爾值。
 
 
2.部署接口
   上面咱們說到的部署接口,那js怎麼部署接口呢。其實咱們以前已經說到過,在Symbol一節中,介紹了不少es6內置的Symbol值,這些就是接口。
  es6中有三類結構生來就具備Iterator接口:數組、類數組對象、Map和Set結構。
  
var arr = [1,2,3,4];
let iterator = arr[Symbol.iterator]();

console.log(iterator.next());  //{ value: 1, done: false }
console.log(iterator.next());  //{ value: 2, done: false }
console.log(iterator.next());  //{ value: 3, done: false }
console.log(iterator.next());  //{ value: 4, done: false }
console.log(iterator.next());  //{ value: undefined, done: true }
 
 
   至於對象沒有佈置iterator接口的緣由,不知道最近你們有沒有看根據《你一輩子的故事》拍成的電影「降臨",片中出現的外星語言是一門非線性的語言。而咱們說的數組,Map等結構中的成員都是有順序的,即都是線性的結構,而對象,各成員並無一個肯定的順序,因此遍歷時先遍歷誰後遍歷誰並不肯定。因此,給一個對象部署iterator接口,其實就是對該對象作一種線性轉換。若是你有這種須要,就須要手動給你的對象部署iterator接口咯~
  如:
  
let obj = {
    data: [ 'hello', 'world' ],
    [Symbol.iterator]() {
        const self = this;
        let index = 0;
        return {
            next() {
                if (index < self.data.length) {
                    return {
                        value: self.data[index++],
                        done: false
                    };
                } else {
                    return { value: undefined, done: true };
                }
            }
        };
    }
};

 

 
   能夠看到,Symbol.iterator會返回一個對象,這就是一個遍歷器對象,而做爲遍歷器對象,其必須具有的特徵就是必須具有next()方法。
咱們還能夠據此實現指針結構的數據結構。具體略~
 
  至於可使用Array.from轉換成數組的類數組對象,部署iterator有一種很簡單的方法,即直接使用數組的[Symbol.iterator]接口。
  
fakeArray.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

 

  固然,不知道大家看到next是否想到了es6的一個新玩意兒,即Generator函數。用Generator函數來實現Symbol.iterator接口,事半功倍。
  
var yieldIterator = {};
yieldIterator[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};

[...yieldIterator] // [1, 2, 3]
 
   注意,yield* 後面跟的是一個可遍歷的結構,它會調用該結構的遍歷器接口。
  其次,其它調用到遍歷器的操做還有解構賦值、擴展操做符、其它任何接受數組做爲參數的場合,如:
  • for...of
  • Array.from()
  • Map(), Set(), WeakMap(), WeakSet()(好比)
  • Promise.all()
  • Promise.race()
 
 
  一旦當你給你的結構部署了iterator接口,那麼恭喜你,你可使用for...of來遍歷你的結構了!
 
  遍歷器對象除了必須佈置next方法之外,還有2個可選方法。return()和throw()。當一個解構在遍歷的時候異常提早退出(好比break,continue或者出錯)的時候,就會調用return方法,其次,return方法必須返回一個對象。
至於throw方法,則是用於拋出錯誤,Generator.prototype.throw這裏不展開講了,感興趣的能夠搜索一下。
 
  for of循環有不少優勢,好比不像for...in同樣只遍歷鍵名(甚至包括原型鏈上的鍵),並且不像foreach不能跳出循環。而且for...of爲各類數據結構提供了一個統一的遍歷方法。因此,儘可能使用它吧~
相關文章
相關標籤/搜索