深入理解ES6之迭代器与生成器
迭代器
迭代器 iterator,在 Javascript 中,迭代器是一個對象(也可稱作為迭代器對象),它提供了一個 next() 方法,用來返回迭代序列中的下一項。
next 方法的定義,next 方法是一個函數,執行后返回一個對象包含兩個屬性:{ done: [boolean], value: [any] }
function makeIterator(array) {var nextIndex = 0return {next() {return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { done: true }}} }// iterator 是一個迭代器對象 var iterator = makeIterator([10, 20, 30]) iterator.next() // {value: 10, done: false} iterator.next() // {value: 20, done: false} iterator.next() // {value: 30, done: false} iterator.next() // {done: true}可迭代對象
可迭代對象必須實現一個 @@iterator 方法,也就是說在這個對象或者它的原型鏈上必須有一個方法名是 Symbol.iterator 的方法,當調用這個方法時它返回一個迭代器對象。
可迭代對象的表現形式為,可以使用 for...of 循環,解構賦值,拓展運算符(spread),yield* 這些語法來調用 Symbol.iterator 函數。也就是說這些語法糖在被調用時本質上都是在調用 Symbol.iterator 函數。
內置可迭代對象
String,Array,TypedArray,Map,Set,函數的arguments對象,NodeList對象都是內置的可迭代對象,他們的原型對象中都有一個 Symbol.iterator 方法。
// 可迭代對象 let iterable = [10, 20, 30] // 繼承自原型鏈 Symbol.iterator in iterable // true iterable.hasOwnProperty(Symbol.iterator) // falsefor(let value of iterable){console.log(value) } // 10 // 20 // 30自定義可迭代對象
字面量對象 let o = {} 默認沒有 Symbol.iterator 方法,但是我們在對象上自定義一個 @@iterator 方法,此時字面量對象也可以使用 for...of循環,拓展運算符等等語法糖。
// 字面量對象默認是不可迭代對象 // 自定義對 var myIterable = {} myIterable[Symbol.iterator] = function(){return {arr: [10, 20, 30],next: function(){if(this.arr.length > 0){return {value: this.arr.shift(), done: false}}else{return {done: true}}}} } [...myIterable] // [10, 20, 30]生成器
生成器 generator,在 Javascript 中生成器是一個函數(也可稱作生成器函數),它可以作為創建迭代器的工廠函數。生成器函數的返回值是一個迭代器對象,同時這個對象也是一個可迭代對象。
funtion* name(){ //statement } 這種聲明方式可以定義一個生成器函數。
生成器函數的語法規則是,調用一個生成器函數并不會馬上執行它里面的語句,而是返回一個這個生成器的 迭代器(iterator)對象。當這個迭代器的 next() 方法被首次(后續)調用時,其內的語句會執行到第一個(后續)出現yield的位置為止,yield 后緊跟迭代器要返回的值。或者如果用的是 yield*(多了個星號),則表示將執行權移交給另一個生成器函數(當前生成器暫停執行)。調用 next() 方法時,如果傳入了參數,那么這個參數會作為上一條執行的 yield 語句的返回值。
// 生成器函數 function* generator(i){yield i + 1var y = yield 'foo'yield y }var iterator = generator(10) // 此時生成器函數不執行,返回一個迭代器iterator.next() // {value: 11, done: false} iterator.next() // {value 'foo', done: false} iterator.next(10) // {value: 10, done: false},將10賦值給上一條 yield 'foo' 左側的值,即 y = 10,返回 y iterator.next() // {done: true}既然 生成器函數 可以創建 迭代器對象,我們來試著將前面的例子用生成器函數的形式重寫試試看。
// 生成器函數 function* makeIterator(array) {for (let i = 0; i < array.length; i++) {yield array[i]} }// 迭代器對象,實現和上文一樣的功能 var iteratorByGen = makeIterator([10, 20, 30]) iteratorByGen.next() // {value: 10, done: false} iteratorByGen.next() // {value: 20, done: false} iteratorByGen.next() // {value: 30, done: false} iteratorByGen.next() // {done: true}從上面的代碼我們可以看到,利用生成器函數來創建一個迭代器對象的方式相比于之前我們普通函數創建的方式更加簡潔,也更加清晰的表明調用生成器函數返回的是一個迭代器對象。除此之外還有什么區別呢。
上文已經提到,生成器函數返回的是一個 可迭代的迭代器對象,這是什么意思呢?看下代碼就明白了。
// 生成器函數創建的迭代器對象 Symbol.iterator in iteratorByGen // true [...iteratorByGen] // [10, 20, 30]// 普通函數創建的迭代器對象 Symbol.iterator in iterator // false [...iterator] // Uncaught TypeError: iterator is not iterable綜上所述,我們可以確定的說 生成器函數是創建迭代器對象的語法糖 ,通過生成器函數我們可以用很簡潔清晰的語法創建一個可迭代的迭代器對象。
來源:https://segmentfault.com/a/1190000017529530
轉載于:https://www.cnblogs.com/qixidi/p/10185861.html
總結
以上是生活随笔為你收集整理的深入理解ES6之迭代器与生成器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++基础(上) 听课流水账
- 下一篇: 显示器尺寸对照表_求解显示器屏幕尺寸对照