詳解ES6文法之可迭代協議和迭代器協議,詳解es6

來源:互聯網
上載者:User

詳解ES6文法之可迭代協議和迭代器協議,詳解es6

ECMAScript 2015的幾個補充,並不是新的內建或文法,而是協議。這些協議可以被任何遵循某些約定的對象來實現。
有兩個協議:可迭代協議和迭代器協議。

可迭代協議

可迭代協議允許 JavaScript 對象去定義或定製它們的迭代行為, 例如(定義)在一個 for..of 結構中什麼值可以被迴圈(得到)。一些內建類型都是內建的可迭代對象並且有預設的迭代行為, 比如 Array or Map, 另一些類型則不是 (比如Object) 。

Iterator 介面的目的,就是為所有資料結構,提供了一種統一的訪問機制,即for...of迴圈(詳見下文)。當使用for...of迴圈遍曆某種資料結構時,該迴圈會自動去尋找 Iterator 介面,調用Symbol.iterator方法,返回該對象的預設遍曆器。

ES6 規定,預設的 Iterator 介面部署在資料結構的Symbol.iterator屬性,或者說,一個資料結構只要具有Symbol.iterator屬性,就可以認為是“可迭代的”(iterable)。Symbol.iterator屬性本身是一個函數,就是當前資料結構預設的遍曆器產生函數。執行這個函數,就會返回一個遍曆器。

為了變成可迭代對象, 一個對象必須實現(或者它原型鏈的某個對象)必須有一個名字是 Symbol.iterator 的屬性:

迭代器協議

該迭代器協議定義了一種標準的方式來產生一個有限或無限序列的值。

JavaScript 原有的表示“集合”的資料結構,主要是數組(Array)和對象(Object),ES6 又添加了Map和Set。這樣就有了四種資料集合,使用者還可以組合使用它們,定義自己的資料結構,比如數組的成員是Map,Map的成員是對象。這樣就需要一種統一的介面機制,來處理所有不同的資料結構。

迭代器(Iterator)就是這樣一種機制。它是一種介面,為各種不同的資料結構提供統一的訪問機制。任何資料結構只要部署 Iterator 介面,就可以完成遍曆操作(即依次處理該資料結構的所有成員)。

Iterator 的作用有三個:一是為各種資料結構,提供一個統一的、簡便的提供者;二是使得資料結構的成員能夠按某種次序排列;三是 ES6 創造了一種新的遍曆命令for...of迴圈,Iterator 介面主要供for...of消費。

Iterator 的遍曆過程是這樣的。

  1. 建立一個指標對象,指向當前資料結構的起始位置。也就是說,遍曆器對象本質上,就是一個指標對象。
  2. 第一次調用指標對象的next方法,可以將指標指向資料結構的第一個成員。
  3. 第二次調用指標對象的next方法,指標就指向資料結構的第二個成員。
  4. 不斷調用指標對象的next方法,直到它指向資料結構的結束位置。

每一次調用next方法,都會返回資料結構的當前成員的資訊。具體來說,就是返回一個包含value和done兩個屬性的對象。其中,value屬性是當前成員的值,done屬性是一個布爾值,表示遍曆是否結束。

var someString = "hi";typeof someString[Symbol.iterator]; // "function"var iterator = someString[Symbol.iterator]();iterator + "";  // "[object String Iterator]"iterator.next()    // { value: "h", done: false }iterator.next();   // { value: "i", done: false }iterator.next();   // { value: undefined, done: true }

原生具備 Iterator 介面的資料結構如下。

  1. Array
  2. Map
  3. Set
  4. String
  5. TypedArray
  6. 函數的 arguments 對象
  7. NodeList 對象

注意對象是不具備 Iterator 介面的,一個對象如果要具備可被for...of迴圈調用的 Iterator 介面,就必須在Symbol.iterator的屬性上部署遍曆器產生方法(原型鏈上的對象具有該方法也可)。

調用 Iterator 介面的場合

有一些場合會預設調用 Iterator 介面(即Symbol.iterator方法),除了下文會介紹的for...of迴圈,解構賦值, 擴充運算子其實也會調用預設的Iterator 介面。

實際上,這提供了一種簡便機制,可以將任何部署了 Iterator 介面的資料結構,轉為數組。也就是說,只要某個資料結構部署了 Iterator 介面,就可以對它使用擴充運算子,將其轉為數組。

由於數組的遍曆會調用遍曆器介面,所以任何接受數組作為參數的場合,其實都調用了遍曆器介面。下面是一些例子。

  1. for...of
  2. Array.from()
  3. Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]]))
  4. Promise.all()
  5. Promise.race()

for...of

for...of 迴圈是最新添加到 JavaScript 迴圈系列中的迴圈。

它結合了其兄弟迴圈形式 for 迴圈和 for...in 迴圈的優勢,可以迴圈任何可迭代(也就是遵守可迭代協議)類型的資料。預設情況下,包含以下資料類型:String、Array、Map 和 Set,注意不包含 Object 資料類型(即 {})。預設情況下,對象不可迭代。

在研究 for...of 迴圈之前,先快速瞭解下其他 for 迴圈,看看它們有哪些不足之處。

for 迴圈

for 迴圈的最大缺點是需要跟蹤計數器和允出準則。我們使用變數 i 作為計數器來跟蹤迴圈並訪問數組中的值。我們還使用 Array.length 來判斷迴圈的允出準則。

雖然 for 迴圈在迴圈數組時的確具有優勢,但是某些資料結構不是數組,因此並非始終適合使用 loop 迴圈。

for...in 迴圈

for...in 迴圈改善了 for 迴圈的不足之處,它消除了計數器邏輯和允出準則。但是依然需要使用 index 來訪問數組的值.

此外,當你需要向數組中添加額外的方法(或另一個對象)時,for...in 迴圈會帶來很大的麻煩。因為 for...in 迴圈逐一查看所有可枚舉的屬性,意味著如果向數組的原型中添加任何其他屬性,這些屬性也會出現在迴圈中。這就是為何在逐一查看數組時,不建議使用 for...in 迴圈。

注意: forEach 迴圈 是另一種形式的 JavaScript 迴圈。但是,forEach() 實際上是數組方法,因此只能用在數組中。也無法停止或退出 forEach 迴圈。如果希望你的迴圈中出現這種行為,則需要使用基本的 for 迴圈。

for...of 迴圈

for...of 迴圈用於逐一查看任何可迭代的資料類型。

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];for (const digit of digits) { console.log(digit);}

可以隨時停止或退出 for...of 迴圈。

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];for (const digit of digits) { if (digit % 2 === 0) {  continue; } console.log(digit); //1,3,5,7,9}

不用擔心向對象中添加新的屬性。for...of 迴圈將只逐一查看對象中的值。

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.