【前端】【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為各種數據結構提供了一個統一的遍歷方法。所以,盡量使用它吧~
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM