1. 程式人生 > 其它 >【JS】從ECMA深入學習Iterator的執行機制和原理

【JS】從ECMA深入學習Iterator的執行機制和原理

技術標籤:Javascript前端javascriptes6

前置:前後加了 % 代表著這是 ECMAScript 內部抽象化的語言表現形式。例如:我們看到的 Object.prototype 在語言內部抽象後所表現的就是 %ObjectPrototype%。其實所代表的就是 Object 的 原型方法。JS

Iterator遍歷器


ES中,Array、Object、Map、Set是表示“集合”的資料結構。從抽象一些的角度來看,它們都是由多個元素/資料組合而成的。Iterator就是一種介面,為不同的資料結構提供同意的訪問機制。ES6中,如果要使用for...of...yield*

來訪問變數,就必須要實現Iterator介面。

iterator介面內容

  • next()方法(必選):返回值為IteratorResult物件
  • return()方法(可選):返回一個done為true的IteratorResult,呼叫這個方法表示後續不能再進行next方法了
  • throw()方法(可選):呼叫此方法表示遍歷過程當中出現錯誤。

IteratorResult介面

屬性型別描述
donetrue/falsedone不存在預設為false,如果遍歷到結束位置,為true
value任意型別value值不一定會返回,done為false返回遍歷到的當前元素,done為true返回this物件。

ES6文件中,提到所有實現了Iterator介面的物件,都繼承了%IteratorPrototype% Object。我們就來看看這個物件包括什麼。

遍歷器原型物件(%IteratorPrototype% Object)

ES6規範中,提供了可以直接獲取到%IteratorPrototype% Object的程式碼:

Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()))

ecma262/#sec-%iteratorprototype%-object

我們可以看到,這個物件當中有個名為[Symbol.iterator]的方法。該方法最後返回this。
Symbol.iterator.PNG

既然每個實現Iterable都繼承了這個原型物件,那麼說明,實現Iterable物件的話也需要實現[Symbol.iterator]()

這個方法。

  • 用ts程式碼表示Iterable介面可以表現如下
interface Iterable{
  [Symbol.iterator]():Iterator
}
interface Iterator{
  next(value?:any):IteratorResult
}
interface Iterator{
  value:any,
  done:boolean
}

es6.ruanyifeng.com/#docs/iterator

因此,我們可以看到如果一個數據結構具有Symbol.iterator屬性,就可以認為是可遍歷的。可以使用for…of去迴圈。

iterator遍歷過程

  • 建立一個指標物件,指向當前資料結構的起始位置。
  • 呼叫指標物件的next昂法,把指標指向資料結構的第一個成員。
  • 繼續呼叫next,指標指向下一個成員。直到當前的位置已經超出了陣列的長度,說明已經到達結束位置了。
//實現一個iterator
//定義一個方法,傳入一個物件,返回一個可列舉的物件,
//呼叫next方法會輸出傳入obj裡面的key-value值
//(暫時認為物件取值只包含數字和字串)
Input: var obj = {
    'pos1':1,
     'pos2':2
     'pos3':3
}
Output:
  {value:{'pos1':1},done,false},
  {value:{'pos2':2},done,false},
  {value:{'pos3':3},done,false},

什麼時候呼叫Iterator介面

  • 解構賦值
  • 擴充套件運算子
  • yield*
  • for…of、Array.from、Map(),Set(),WeakMap(),WeakSet(),promise.all,promise.race