Iterator(迭代器)

迭代器(Iterator):它是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構,只要部署了Iterator接口,就能夠完成遍歷(這裏主要指for...of)操做。數組

在ES6中,有三類數據結構原生具有Iterator接口:數組、相似數組的對象、以及Set和Map結構。bash

爲了讓一個對象可遍歷,咱們須要爲這個對象添加一個名爲Symbol.iterator的方法(一個特殊的內置標記)。 想要讓for...of去循環這個對象必須通過下列步驟:數據結構

  • 當使用for...of去遍歷對象時,首先會去找該對象有沒有一個名爲Symbol.iterator的方法(若是沒有找到將會報錯)
  • for...of循環開始時,將會調用這個Symbol.iterator方法
  • 該方法必須返回一個迭代器對象(且裏面含有next方法)
  • 當for...of循環開始去獲取對象的值的時候,它就會調用next方法來獲取
  • next()方法返回的結果是對象的形式{value: '任何值均可以', done: false}或{value:undefined, done: true}; value也就是你要獲取的值,done表示你要獲取的值是否已經所有獲取完畢(迭代是否結束了)。若已經所有獲取了,done就爲true,此後再調用next方法時,done仍是true。

如下是模擬next方法返回值的例子函數

let arr = [5,10,15];
  function Iterator(arr) {
    let index = 0;
    return {
      next () {
        if(index < arr.length) {
          return {value: arr[index++],done: false};
        } else {
          return {value: undefined,done: false};
        }
      }
    }
  }
  let it = Iterator(arr);
  console.log(it.next()); //{value: 5, done: false}
  console.log(it.next()); //{value: 10, done: false}
  console.log(it.next()); //{value: 15, done: false}
  console.log(it.next()); //{value: undefined, done: false}
  console.log(it.next()); //{value: undefined, done: false}
複製代碼

以上代碼定義了一個Iterator函數,這個函數是遍歷器生成函數(至關於Symbol.iterator方法),以後會說到Symbol.iterator方法,調用這個函數時,會返回一個迭代器對象。再調用next()方法就會返回{value:'任何值',done:Boolean}對象。next方法用來移動指針,第一次調用時,指針指向數組的第一個位置;第二次調用時,指向第二個位置......這樣就能夠遍歷到數組的每個位置,進而獲取數組的每一個元素的值ui

let arrayLike = {
    0: 'name',
    1: 'age',
    2: 'address',
    length: 3
  };
  Object.prototype[Symbol.iterator] = function () {
    let index = 0;
    let current = this;
    return {
      next () {
        if(index < current.length) {
          return {value: current[index++], done: false};
        } else {
          return {value: undefined, done: true}
        }
      }
    }
  };
  //這樣當使用for...of循環時會去自動調用Symbol.iterator()方法,返回一個迭代器對象以後
  //又會去調用next方法
  for(let i of arrayLike) {
    console.log(i);  //name age address
  }
複製代碼

還能夠經過類部署Iterator接口。Symbol.iterator屬性對於一個函數,執行後返回當前對象的迭代器對象。this

class Iterator {
    constructor (obj) {
      this.start = 0;
      this.end = obj.length
    }
    [Symbol.iterator] () {
      return this;
    }
    next () {
      if(this.start < this.end) {
        return {value: obj[this.start++], done: false};
      } else {
        return {value: undefined, done: true};
      }
    }
  }
  let obj = {
    0: 'name',
    1: 'age',
    length: 2
  };
  let it = new Iterator(obj);
  // console.log(it.next());
  // console.log(it.next());
  // console.log(it.next());
  for(let j of it) {
    console.log(j);  //name age
  }
複製代碼

對於相似數組的對象(存在鍵值名和length屬性),部署Iterator接口有一個的簡便方法就是對象的Symbol.iterator直接引用數組的Symbol.iterator。以下所示:spa

let obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3,
    [Symbol.iterator]: Array.prototype[Symbol.iterator]
  };
  for(let j of obj) {
    console.log(j);  //將會打印出a,b,c
  }
複製代碼

注意普通對象部署Symbol.iterator方法並沒有效果 prototype

字符串也是能夠迭代的 : for...of循環能夠將字符串的每一個字符循環出來指針

let str = 'hello';
for(let j of str) {
    console.log(j);  // h e l l o
}
複製代碼
相關文章
相關標籤/搜索