最近看阮一峯阮大神的ES6,剛剛看到Iterator和for...of循環這一章,小做筆記跟你們略微分享一下,不足之處還望你們多多指正es6
Iterator(遍歷器)就是一種機制;任何數據結構只要是部署了iterator接口,就能夠完成遍歷操做(即依次處理該數據的全部成員);數組
Iterator的做用有三個:一是爲各類數據結構,提供一個統一的、簡便的訪問接口;二是使得數據結構的成員可以按某種次序排列;三是ES6創造了一種新的遍歷命令for...of循環,Iterator接口主要供for...of消費。(阮大神原話);數據結構
只要是一個對象部署了Symbol.interator接口,就能夠用for...of遍歷該對象,同時也能夠調用該接口的Symbol.interator方法調用next()方法對對象進行遍歷,不一樣的是for..of是對該對象的值的輸出,而next()返回的是對象。
例以下面的例子:函數
若是調用next方法就是this
調用next()方法會返回一個對象{value:value;done:true or false};直到對遍歷對象的值便利完成以後,next()方法會返回一個{value:undefined; done:true}表明已經遍歷完成,再調用next()方法也不會報錯可是依舊會返回{value:undefined; done:true};spa
有一些對象是原生就封裝好的Symbol.iterator接口,能夠直接調用,固然也能夠直接用for...of遍歷;
在ES6中,有三類數據結構原生具有Iterator接口:數組、某些相似數組的對象、Set和Map結構。
若是沒有原生的Symbol.iterator接口,想用for...of遍歷,就須要本身在該對象中部署Symbol.iterator接口,例如prototype
一個對象若是要有可被for...of循環調用的Iterator接口,就必須在Symbol.iterator的屬性上部署遍歷器生成方法(原型鏈上的對象具備該方法也可)。code
一個對象若是要有可被for...of循環調用的Iterator接口,就必須在Symbol.iterator的屬性上部署遍歷器生成方法(原型鏈上的對象具備該方法也可)。 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}; } else { return {done: true, value: undefined}; } } } function range(start, stop) { return new RangeIterator(start, stop); } for (var value of range(0, 3)) { console.log(value); }//阮大神案例
上面代碼是一個類部署Iterator接口的寫法。Symbol.iterator屬性對應一個函數,執行後返回當前對象的遍歷器對象。
原型鏈上部署Symbol.iterator接口對象
function Obj(value){ this.value = value; this.next = null; } Obj.prototype[Symbol.iterator] = function(){ var iterator = { next: next }; var current = this; function next(){ if (current){ var value = current.value; var done = current == null; current = current.next; return { done: done, value: value } } else { return { done: true } } } return iterator; } var one = new Obj(1); var two = new Obj(2); var three = new Obj(3); one.next = two; two.next = three; for (var i of one){ console.log(i) } // 1 // 2 // 3
對象內部部署接口
let obj = { data: [ 'hello', 'world' ], [Symbol.iterator]() { const self = this; let index = 0; return { next() { if (index < self.data.length) { return { value: self.data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } };
也就是說若是一個對象沒有Symbol.iterator接口,能夠在類自己上面部署,也能夠在原型連上部署,也能夠在對象內部部署
對於相似數組的對象(存在數值鍵名和length屬性),部署Iterator接口,有一個簡便方法,就是Symbol.iterator方法直接引用數組的Iterator接口。
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; // 或者 NodeList.prototype[Symbol.iterator] = [][Symbol.iterator]; [...document.querySelectorAll('div')] // 能夠執行了
具體請看例子
let iterable = { 0: 'a', 1: 'b', 2: 'c', length: 3, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; for (let item of iterable) { console.log(item); // 'a', 'b', 'c' }
**可是請記住,這個方法僅僅適用於類數組對象,上面的也能夠直接用Array.from(iterable)轉換成數組來遍歷,例如
let arrayLike = { length: 2, 0: 'a', 1: 'b' }; for (let x of Array.from(arrayLike)) { console.log(x); }//a b
對於普通對象這兩個方法是無論用的,**例如
let iterable = { edition: 'a', writer: 'b', read: 'c', length: 3, }; for (let item of Array.from(iterable)) { console.log(item); }
上面的代碼就會輸出三個undefined
let iterable = { edition: 'a', writer: 'b', read: 'c', length: 3, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; for (let item of iterable) { console.log(item); //報錯 }
上面的代碼就會拋異常的;
其實ES6不少地方都用的到Iterator這個接口,例如:
解構賦值
擴展運算符
yield*
最後須要說下,字符串既是類數組對象同時本身也有原生Symbol.iterator接口能夠直接調用,例如
var str = "hell";
for(let v of str){
console.log(v);//"h","e","l","l"
}
對於字符串來講,for...of循環還有一個特色,就是會正確識別32位UTF-16字符。
for...of 區別於for循環,for循環比較麻煩,可是是最原始的方法;
for...of 區別於數組的forEach方法,由於forEach方法是從頭至尾執行,不會跳出,可是遇到break或者return,continue會跳出循環
有着同for...in同樣的簡潔語法,可是沒有for...in那些缺點。
不一樣用於forEach方法,它能夠與break、continue和return配合使用。
提供了遍歷全部數據結構的統一操做接口。
更詳細的請查看阮大神(http://es6.ruanyifeng.com/#docs/iterator)本章內容