1. 程式人生 > 程式設計 >ES6 Iterator遍歷器原理,應用場景及相關常用知識拓展詳解

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方法,它可以與breakcontinuereturn配合使用。
  • 提供了遍歷所有資料結構的統一操作介面。

參考:http://es6.ruanyifeng.com/

感興趣的朋友可以使用線上HTML/CSS/JavaScript程式碼執行工具:http://tools.jb51.net/code/HtmlJsRun測試上述程式碼執行效果。

更多關於JavaScript相關內容可檢視本站專題:《javascript面向物件入門教程》、《JavaScript錯誤與除錯技巧總結》、《JavaScript資料結構與演算法技巧總結》、《JavaScript遍歷演算法與技巧總結》及《JavaScript數學運算用法總結》

希望本文所述對大家JavaScript程式設計有所幫助。