亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

ES6+ 迭代協議

1. 前言

上一節我們對 ES6 新增的 for...of 做了深入的講解,它可以用于字符串、數組、類數組、以及新增的數據結構 Map/Set 等進行遍歷。但是這些能夠使用 for...of 進行遍歷的都有一個共同的特性 —— 可迭代。那什么是可迭代呢?

ECMAScript 2015 在一組補充規范中規定了兩個協議:可迭代協議和迭代器協議。這兩個規定不是新的內置實現或語法,而是協議。這些協議可以被任何數據結構遵循,從而可以實現自定義的遍歷,而這些遵守迭代協議的數據結構是可以被 for...of 遍歷的。有了這樣的一個規范,我們所定義的數據結構就會更加豐富了,本節我們將深入 ES6 中的迭代。

2. 可迭代協議和迭代器協議

迭代協議包括兩方面的內容 —— 可迭代協議和迭代器協議,下面我們就來看看這兩個協議都是什么。

2.1 可迭代協議

什么是可迭代協議?可以通過 JavaScript 對象定義或定制迭代行為,在 JavaScript 中有一些內置類型并且滿足內置的可迭代對象,具有迭代的行為。如 Array、Map、Set 等。還有一個比如字面量對象(Object)則沒有,如果要對 Object 進行迭代的話需要使用 for...in 循環,但是 for...in 在循環時需要判斷是否是自身屬性。所以很多時候如果想用 for...of 進行迭代時就需要使用對象上的 Object.keys() 等方法提取對象中的 keys 后再去進行遍歷操作。

在 ES6 中可迭代協議規定想要成為可迭代對象,這個對象必須實現 @@iterator 方法。這意味著對象(或者它原型鏈上的某個對象)必須有一個鍵為 @@iterator 的屬性,可通過常量 Symbol.iterator 訪問該屬性。所以,一個對象滿足可迭代協議的關鍵在于實現 Symbol.iterator 方法,這個方法的返回值是一個符合迭代器協議的對象,并且是一個無參數的函數。

2.2 迭代器協議

上面說到了在實現 Symbol.iterator 方法時需要返回一個滿足迭代器協議的方法。那么迭代器協議又是什么呢?

迭代器協議定義了產生一系列值的一個標準方式,迭起協議規定需要返回一個帶 next() 方法的對象。 next() 可以被多次執行,每次執行都會返回一個對象,該對象包含兩個屬性,donevalue:

  • done 是一個 boolean,在沒有迭代完時返回 false,迭代完成后返回 true;
  • value 就是被迭代的返回值,當 done 為 true 時可以省略。

實現了以上兩點才會滿足一個迭代器協議。一般來說可迭代協議和迭代器協議在實際的場景中是同時存在的。下面我來看看什么是迭代器?并且怎么使用可迭代協議和迭代協議去實現一個迭代器。

3. 迭代器

這里說的迭代器是遵循上面兩個協議來實現的,在滿足兩個協議時,我們可以顯式地通過不斷調用 next () 方法去進行迭代。在迭代一個迭代器后,我們稱之為消耗了這個迭代器而,且每個迭代器只能執行一次。下面我們來看看怎么實現一個迭代器:

var obj = {}
obj[Symbol.iterator] = function() {
  let index = 1;
  return {
    next() {
      if (index <= 10) {
        return {value: index++, done: false}
      } else {
        return {done: true}
      }
    }
  }
}

上面的代碼中根據可迭代協議給 obj 對象添加一個 Symbol.iterator 方法,再根據迭代器協議返回一個 next() 方法,在每次消耗 next() 時對 index 進行加 1 操作。當 index 大于 10 的時候結束迭代行為,之后再消耗 next() 返回值不變。

根據上面的代碼,我們可以顯式的手動調用 next()

var iterator = obj[Symbol.iterator]();
var s = iterator.next();

while(!s.done) {
  console.log(s.value);
  s = iterator.next();
}
// 1
// 2
// ...

執行上面的代碼,在瀏覽器的控制臺中,可以看到大于的結果是 1 到 10。上面是我們手動執行消耗 next() 的方式,上面我們也說了,只要滿足迭代協議就可以被 for...of 循環,那是不是真的是這樣的呢?下面我們就使用 for...of 對 obj 進行循環。

for (let i of obj) {
  console.log(i)
}
// 1
// 2
// ...

在控制臺中執行上面的代碼,可以看到和我們使用手動調用 next() 方式返回打印的結果是一樣的。

4. 小結

本節我們主要學習了兩個協議 —— 可迭代協議和迭代器協議,并且通過這兩個協議實現了一個迭代器。通過這個迭代器我們知道,在滿足這兩個協議后就可以使用 for...of 進行循環,并且我們進行顯示調用進行了驗證。

插入案例