ES6標準入門之Iterator函數

爲各類不一樣的數據結構提供統一的訪問機制!主要是爲了使用for...of方法javascript

概念

  JavaScript原有的表示'集合'的數據結構,主要是數組和對象。ES6又添加了Set和Map。這樣就須要一種統一的接口機制, 來處理全部不一樣的數據結構。java

  遍歷器就是這樣一種機制,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只要部署了Iterator接口,就能夠完成遍歷操做。數組

Iterator的遍歷過程

  • 建立一個指針對象,指向當前數據結構的起始位置(遍歷起的本質就是一個指針對象)
  • 第一次調用指針對象的next()方法,能夠將指針指向數據結構的第一個成員。
  • 第二次調用就指向第二個成員。
  • 不斷調用,直到指向數據結構結束位置。

說白了,每次調用返回的就是一個對象,裏面包括value和done兩個屬性。value屬性是當前成員的值,done屬性是一個布爾值,表示遍歷是否結束。數據結構

說了這麼多,拿出個具體的例子🌰解釋一下咯 。async

var it  = makeIterator(['a','b']);
function makeIterator(array) {
   var nextIndex = 0;
   return {
       next:function() {
         nextIndex < array.length ? 
         {value: array[nextIndex++], done: false }:
         {value: undefined, done: true}
       }
   }
}
it.next();
it.next();
複製代碼

上面的代碼定義了一個makeIterator函數,他是一個遍歷器生成函數,做用就是返回一個遍歷器對象。對數組['a','b']執行這個函數,就會返回該數組的遍歷器對象(即指針對象)it。函數

指針對象的next方法,用來移動指針。
next方法返回一個對象,表示數據成員的信息。ui

總之,調用指針對象的next方法,就能夠遍歷事先給定的數據結構。this

默認Iterator接口

定義

Iteratot接口的目的,就是爲全部的數據結構,提供了一種統一的訪問機制,即for...of循環。當使用for...of循環遍歷某種數據結構時,該循環會自動去尋找 Iterator 接口spa

說白了,我理解的Iterator接口的產生,就是爲了使用for...of!指針

一種數據結構,只要部署了Iterator接口,就是可遍歷的,就能用for...of。

ES6規定,默認的Iterator接口部署在數據結構的Symbol.Iterator屬性,也就是說,一個數據結構,只要有Symbol.Iterator屬性,就是可遍歷的。

原生具有Iterator接口的數據結構

  • Array
  • Map
  • Set
  • String
  • TypeArray
  • 函數的arguments對象
  • NodeList 對象

舉個例子吧~ 數組的Symbol.iterator屬性

let arr = ['a', 'b', 'c'];
let arrIterator = arr[Symbol.iterator]();
arrIterator.next();
複製代碼

上面代碼中,變量arr是一個數組,原生就具備遍歷器接口,部署在arr的Symbol.iterator屬性上面。因此,調用這個屬性,就獲得遍歷器對象。 對於原生部署Symbol.iterator屬性的數據結構,能夠直接使用for...of進行循環遍歷。

對象也想用for...of怎麼辦?

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接口的場合

(1)解構賦值 對數組和 Set 結構進行解構賦值時,會默認調用Symbol.iterator方法。

let set = new Set().add('a').add('b').add('c');

let [x,y] = set;
 x='a'; y='b'

let [first, ...rest] = set;
// first='a'; rest=['b','c'];
複製代碼

(2)擴展運算符 擴展運算符(...)也會調用默認的 Iterator 接口。

// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']

// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
複製代碼

(3)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 }
複製代碼

遍歷器對象的 return(),throw()

遍歷器對象除了具備next方法,還能夠具備return方法和throw方法。若是你本身寫遍歷器對象生成函數,那麼next方法是必須部署的,return方法和throw方法是否部署是可選的。

return方法的使用場合是,若是for...of循環提早退出(一般是由於出錯,或者有break語句),就會調用return方法。若是一個對象在完成遍歷前,須要清理或釋放資源,就能夠部署return方法。

function readLinesSync(file) {
  return {
    [Symbol.iterator]() {
      return {
        next() {
          return { done: false };
        },
        return() {
          file.close();
          return { done: true };
        }
      };
    },
  };
}
複製代碼

上面代碼中,函數readLinesSync接受一個文件對象做爲參數,返回一個遍歷器對象,其中除了next方法,還部署了return方法。下面的兩種狀況,都會觸發執行return方法。

說了這麼多,最主要是,仍是爲了調用for...of。

說到遍歷,首先就能想到,for,forEach,while,for...in。

  • for:寫法複雜,不優雅。
  • forEach只能遍歷數組,並且,不能暫停,break你用不了。
  • for...in:隨寫法簡單,可是遍歷出來的是對象的key值,不適合遍歷數組。

那麼,問題來了,for...of有什麼優點呢?

  • 簡單,好理解。
  • 可暫停,能夠配合break,continue和return一塊兒使用
  • 最主要是提供了統一的操做接口

說到底,本節課主要是仍是介紹for...of,介紹Iterator最主要的目的是,爲了Generator函數服務,可是,Generator函數複雜了點兒,接下來咱們還會介紹async...await.

若是你以爲小編寫的不錯,必定要點個贊👍,給個關注呦~

相關文章
相關標籤/搜索