完全理解Iterator模式

首先來看看別人對Iterator都是怎麼理解的?

Iterator是這樣一種機制。
它是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。
任何數據結構只要部署Iterator接口,就能夠完成遍歷操做。
tips: 遍歷操做就是能夠依次處理該數據結構的全部成員。 ---阮一峯ES6入門node


在js中,Iterator是一個對象,它定義一個序列,並在終止時可能返回一個返回值。 具體地說,迭代器經過使用next()方法實現Iterator protocol的任何一個對象。這個對象長這個樣子{value: '任意的值', done: 'true或false'}jquery


個人理解

Iterator是這樣一種機制:編程

  1. 順序訪問一個集合
  2. 使用者無需知道集合的內部結構(封裝)

舉個例子:數據結構

/* 針對一個僅有3個<a>target</a>標籤的頁面來講 */
var arr = [1, 2, 3];
var nodeList = document.getElementsByTagName('p');
var $p = $('a')

// 須要對這3種數據結構進行遍歷
arr.forEach(function (item) {console.log(item)})

for (let i = 0,len = nodeList.length; i < len; i++) {console.log(nodeList(i))}

$a.each(function (key, p) {console.log(key, p)})
複製代碼

要對這3種數據結構進行遍歷,所使用的編程方式是不同的。
可是這3種數據結構是什麼樣咱們是提早知道的。函數

如今提出一個問題,可否有這樣一種函數,能對這三種數據結構進行統一的遍歷處理。
其實jquery已經幫咱們實現一種方法。ui

//假設已經引入了jquery
function each(data) {
    var $data = $(data); //[生成迭代器] 這個$(data)對象就是某種意義上的迭代器
    $data.each(function (key, val) {
        console.log(key, val)
    })
}
複製代碼

$(data)這個對象的好處是:this

  1. 它能夠順序遍歷有序集合
  2. 使用者沒必要知道集合內部結構

UML類圖spa

// 迭代器生成
class Iterator {
    constructor(container) {
        this.list = container.list
        this.index = 0
    }
    
    next() {
        if (this.hasNext()) {
            return {value: this.list[this.index++], done: false}
        }
        return {done: true}
    }
    
    hasNext() {
        if (this.index >= this.list.length) {
            return false
        }
        return true
    }
}

class Container {
    constructor(list) {
        this.list = list
    }
    
    //生成迭代器
    getIterator() {
        return new Iterator(this)
    }
}

// 目標對象
let arr = [1, 2, 3, 4, 5, 6];
// 迭代器模式
let container = new Container(arr); 
//生成迭代器對象
let iterator = container.getIterator(); 
while (iterator.hasNext()) {
    console.log(iterator.next())
}
複製代碼

場景

  1. jQuery each
  2. ES6 Iterator

ES6 Iterator 爲什麼存在?

  • ES6 語法中,有序集合的數據類型已經不少
  • Array Map Set String TypedArray arguments NodeList
  • 須要有一個統一的遍歷接口來遍歷全部數據類型
  • 以上數據類型,都有[Symbol.iterator]屬性
  • 屬性值是函數,執行函數返回一個迭代器
  • 這個迭代器就有next方法可順序迭代子元素
// ES6 Iterator示例
function each(data, callback) {
    //生成迭代器
    let iterator = data[Symbol.iterator]();
    
    let item = {done: false};
    while (!item.done) {
        item = iterator.next();
        if (!item.done) {
            callback(item.value);
        }
    }
}

//ES6 實現
function each(data, callback) {
    for (let item of data) {
        callback(item)
    }
}
複製代碼

Iterator 和 Generator

  • Iterator的價值不限於上述幾個類型的遍歷
  • 還有Generator函數的使用,Generator是生成器,即生成一個迭代器
  • 即只要返回的數據格式符合Iterator接口的要求
  • 便可使用Iterator語法,這就是迭代器模式
funciton* helloworldGenerator() {
    yield 'hello';
    yield 'world';
    return 'ending';
}
var hw = helloworldGenerator();
hw[Symbol.iterator] //f [Symbol.iterator]() { [native code] }
//能夠看到,Generator函數返回的結果,也實現了 Iterator 接口,即返回了一個迭代器
複製代碼

設計原則驗證

  • 迭代器對象和目標對象分離
  • 迭代器將使用者與目標對象隔離開
  • 符合開放封閉原則
相關文章
相關標籤/搜索