行為型:迭代器模式

2023-04-12 06:00:43

定義

  迭代器模式提供一種方法按順序存取一個聚合物件中的各個元素,而又不暴露該物件的內部表示。迭代器模式是目的性極強的模式它主要是用來解決遍歷問題。

es6 中的迭代器

  JS原生的集合型別資料結構,有Array(陣列)和Object(物件),在ES6中,又新增了Map和Set。四種資料結構各自有著自己的內部實現,但對於使用者,我們希望以同樣的一套規則去遍歷它們,所以ES6在推出新資料結構的同時也推出了一套統一的介面機制——迭代器(Iterator)

  es6 中統一了迭代器迭代介面,任何資料結構只要具備Symbol.iterator屬性(這個屬性就是Iterator的具體實現,它本質上是當前資料結構預設的迭代器生成函數),就可以被遍歷,確切的說是被for...of...迴圈和迭代器的next方法遍歷,for...of...的背後正是對next方法的反覆呼叫。

  在ES6中,針對Array、Map、Set、String、TypedArray、函數的 arguments 物件、NodeList 物件這些原生的資料結構都可以通過for...of...進行遍歷。

模擬實現迭代器

  迭代就是不斷的去拿下一個值的一個過程,以及遍歷完的狀態,是否完成遍歷。

閉包寫法

// 定義生成器函數,入參是任意集合
function iteratorGenerator(list) {
    // idx記錄當前存取的索引
    let idx = 0
    // len記錄傳入集合的長度
    let len = list.length
    return {
        // 自定義next方法
        next: function() {
            // 如果索引還沒有超出集合長度,done為false
            let done = idx >= len
            // 如果done為false,則可以繼續取值
            let value = !done ? list[idx++] : undefined
            
            // 將當前值與遍歷是否完畢(done)返回
            return {
                done: done,
                value: value
            }
        }
    }
}

let iterator = iteratorGenerator(['1號選手', '2號選手', '3號選手'])
iterator.next()
iterator.next()
iterator.next()

generator 寫法

在es6 中生成器函數 function * xxx 可以返回生成器物件( Generator 物件由生成器函數返回並且它符合可迭代協定迭代器協定。)

生成器函數在執行時能暫停,後面又能從暫停處繼續執行。

// 生成器函數寫法
function* iteratorGenerator1(list) {
    yield '生成器函數,我是1號'
    yield '生成器函數,我是2號'
    yield '生成器函數,我是3號'
}

let iterator1 = iteratorGenerator1()
console.log(iterator1.next())
console.log(iterator1.next())
console.log(iterator1.next())

// 生成器函數寫法--優化
function* iteratorGenerator2(list) {
    let index = 0, len = list.length;
    while (index <= len - 1) {
        
        yield list[index]
        index++
    }
   
}

let iterator2 = iteratorGenerator2(['生成器函數優化,我是1號', '生成器函數優化,我是2號', '生成器函數優化,我說3號'])
console.log(iterator2.next())
console.log(iterator2.next())
console.log(iterator2.next())

小結

可迭代協定:具備Symbol.iterator

迭代器協定:一個類似這個結構的物件:

{
	next: function () {
 	 return {
   		value: 'xx', // 當前遍歷節點的值
   		done: false  // 是否完成遍歷
    }
  }
}