ES6 Iterator遍歷器原理,應用場景及相關常用知識拓展詳解
本文例項講述了ES6 Iterator遍歷器原理,應用場景及相關常用知識拓展。分享給大家供大家參考,具體如下:
介紹Iterator之前先列舉下js的表示資料集合結構的幾種方式:
在es6之前有 Array,Object,es6新增了 map,set,當然使用者也可以組合使用這幾種資料結構,靈活儲存資料。
但是當資料結構變得複雜後,怎樣取到裡面的資料就也相對複雜,這就需要有一種讀取資料的統一的介面機制,來處理不同的資料結構。
遍歷器就是這樣一種介面機制,Iterator是一種介面,為不同資料結構提供統一的介面機制。
相應的任何資料結構只要部署Iterator介面,就可以完成遍歷操作。
Iterator的作用:
1,為各種資料結構提供一種統一的,簡單的訪問介面;
2,使得資料結構的成員能夠按照某種次序排列;
3,ES6提供了一種新的遍歷迴圈(for......of.....),Iterator被for......of.....迴圈呼叫;
Iterator本質:
遍歷器本質上是一種指標物件,指標物件上有next()方法,第幾次呼叫就指向第幾個成員
Iterator上next()方法呼叫返回:
1,返回當前成員的資訊
2,返回遍歷是否結束
模擬實現Iterator
var it = makeIterator(['a','b']); it.next() // { value: "a",done: false } it.next() // { value: "b",done: false } it.next() // { value: undefined,done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++],done: false} : {value: undefined,done: true}; } }; }
使用Typescript
interface Iterable { [Symbol.iterator]() : Iterator,} interface Iterator { next(value?: any) : IterationResult,} interface IterationResult { value: any,done: boolean,}
關於預設的Iterator介面:
ES6 規定,預設的 Iterator 介面部署在資料結構的Symbol.iterator
屬性,或者說,一個數據結構只要具有Symbol.iterator
屬性,就可以認為是“可遍歷的”(iterable)。
Symbol.iterator的本質:
1,Symbol.iterator本身是一個函式,對應當前資料結構預設的遍歷器生成函式;
2,執行Symbol.iterator這個函式會返回一個遍歷器。
例項:
const obj = { [Symbol.iterator] : function () { return { next: function () { return { value: 1,done: true }; } }; } }; //這樣定義後物件就有了Iterator介面 //執行物件obj的symbol.iterator後,返回一個遍歷器
具有原生iterator的資料結構:
Array,Map,Set,String,TypedArray,函式的argulements物件,NodeList物件(節點物件);
陣列iterator例項
let arr = ['a','b','c']; let iter = arr[Symbol.iterator](); iter.next() // { value: 'a',done: false } iter.next() // { value: 'b',done: false } iter.next() // { value: 'c',done: false } iter.next() // { value: undefined,done: true }
物件iterator介面實現
class RangeIterator { constructor(start,stop) { this.value = start; this.stop = stop; } [Symbol.iterator]() { return this; } next() { var value = this.value; if (value < this.stop) { this.value++; return {done: false,value: value}; } return {done: true,value: undefined}; } } function range(start,stop) { return new RangeIterator(start,stop); } for (var value of range(0,3)) { console.log(value); // 0,1,2 }
注意:如果一個物件沒有iterator介面,而其原型鏈上有Iterator介面,也可以通過繼承而擁有該介面;
使用while
迴圈遍歷
var $iterator = ITERABLE[Symbol.iterator](); var $result = $iterator.next(); while (!$result.done) { var x = $result.value; // ... $result = $iterator.next(); }
基本概念基本就是這些,接下來看下使用場景
Iterator的使用場景:
預設呼叫場景:
for....of...迴圈, 解構賦值, 擴充套件運算子, yield*關鍵字
ES6 借鑑 C++、Java、C# 和 Python 語言,引入了for...of
迴圈,作為遍歷所有資料結構的統一的方法
這裡主要介紹下yield*,其餘幾個都比較好理解
yield*
後面跟的是一個可遍歷的結構,它會呼叫該結構的遍歷器介面
let generator = function* () { yield 1; yield* [2,3,4];//執行時預設遍歷陣列 yield 5; }; var iterator = generator(); iterator.next() // { value: 1,done: false } iterator.next() // { value: 2,done: false } iterator.next() // { value: 3,done: false } iterator.next() // { value: 4,done: false } iterator.next() // { value: 5,done: false } iterator.next() // { value: undefined,done: true }
其他場景:
由於陣列的遍歷會呼叫遍歷器介面,所以任何接受陣列作為引數的場合,其實都呼叫了遍歷器介面
- for...of
- Array.from()
- Map(),Set(),WeakMap(),WeakSet()(比如
new Map([['a',1],['b',2]])
) - Promise.all()
- Promise.race()
知識拓展:
遍歷器物件的 return(),throw()
return方法在迴圈退出或者報錯時呼叫
throw
方法主要是配合 Generator 函式使用(詳見generator)
計算生成的資料結構
在原有資料結構基礎上計算生成的資料結構,例如Object,Array的entries(),keys(),value()方法生成的資料結構,預設具有iterator介面
類似陣列物件
常見:字串,NodeList節點物件,引數arguments
1,並不是所有類似陣列的物件都具有 Iterator 介面
2,對於類陣列物件可以通過Array.From()將類陣列物件轉化為陣列物件
3,for-of可以識別32 位 UTF-16 字元
for (let x of 'a\uD83D\uDC0A') { console.log(x); }
for-of和其他遍歷方法對比:
for迴圈,forEach迴圈,for...in...迴圈
forEach迴圈無法中途跳出
for...in
迴圈有幾個缺點(for...in
迴圈主要是為遍歷物件而設計的,不適用於遍歷陣列),
- 陣列的鍵名是數字,但是
for...in
迴圈是以字串作為鍵名“0”、“1”、“2”等等。 for...in
迴圈不僅遍歷數字鍵名,還會遍歷手動新增的其他鍵,甚至包括原型鏈上的鍵。- 某些情況下,
for...in
迴圈會以任意順序遍歷鍵名。
對於for...of...
- 有著同
for...in
一樣的簡潔語法,但是沒有for...in
那些缺點。 - 不同於
forEach
方法,它可以與break
、continue
和return
配合使用。 - 提供了遍歷所有資料結構的統一操作介面。
參考:http://es6.ruanyifeng.com/
感興趣的朋友可以使用線上HTML/CSS/JavaScript程式碼執行工具:http://tools.jb51.net/code/HtmlJsRun測試上述程式碼執行效果。
更多關於JavaScript相關內容可檢視本站專題:《javascript面向物件入門教程》、《JavaScript錯誤與除錯技巧總結》、《JavaScript資料結構與演算法技巧總結》、《JavaScript遍歷演算法與技巧總結》及《JavaScript數學運算用法總結》
希望本文所述對大家JavaScript程式設計有所幫助。