遍歷Array能夠採用下標循環,遍歷Map和Set就沒法使用下標。爲了統一集合類型,ES6標準引入了新的iterable類型,Array、Map和Set都屬於iteratore類型。
全部的iterator對象都有next()方法,會返回一個結果對象。該結果對象擁有兩個屬性,value和done.
下面的例子模擬生成iteratores6
var it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false } it.next() // { value: "b", done: false } it.next() // { value: undefined, done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; }
上例能夠看出,要生成一個iterator很複雜。幸虧ES6專門提供了generator用來生成iterator.數組
generator 是一個返回迭代器的函數,與普通函數不一樣的是聲明generators函數要在function後面添加"*",同時函數內部使用es6新增長的關鍵字yield來控制next()方法的返回值。數據結構
// generator 函數 function *createIterator(){ yield 1; yield 2; yield 3; } // 建立迭代器 let iterator = createIterator(); console.log(iterator.next().value); // 1 console.log(iterator.next().value); // 2 console.log(iterator.next().value); // 3 console.log(iterator.next().value); // undefined
從上述代碼能夠看出每次的yield使用均可以阻止代碼的執行,當迭代器調用next()方法後纔會繼續執行。
也可使用函數表達式的形式建立generator函數。ide
let createIterator = function *(items){ for(let i=0;i<items.length;i++){ yield items[i]; } } let iterator = createIterator([1,2,3]); console.log(iterator.next()); // "{value:1,done:false}" console.log(iterator.next()); // "{value:2,done:false}" console.log(iterator.next()); // "{value:3,done:false}" console.log(iterator.next()); // "{value:undefined,done:true}" console.log(iterator.next()); // "{value:undefined,done:true}"
注意: 關鍵字yield只能在generator函數內部使用,即便在生成器內部的函數中也不行。以下代碼:函數
function *createIterator(items){ items.forEach(function(item){ yield item + 1; }) } let iterator = createIterator([1,2,3]); console.log(iterator.next()); // "Uncaught SyntaxError: Unexpected identifier"
在對象中建立生成器。code
var o = { createIterator: function *(items) { for(let i =0; i<items.length; i++) { yield items[i]; } } }; let iterator = o.createIterator([1,2,3]);
ES6寫法:orm
var o = { *createIterator(items) { for(let i =0; i<items.length; i++) { yield items[i]; } } }; let iterator = o.createIterator([1,2,3]);
Iterator 接口的目的,就是爲全部數據結構,提供了一種統一的訪問機制,即for...of循環。當使用for...of循環遍歷某種數據結構時,該循環會自動去尋找 Iterator 接口。
一種數據只要部署了Iterator接口,就認爲這種數據是可遍歷的(iterable)。默認的Iterator接口部署在數據結構的Symbol.iterator屬性,或者說,一個數據結構只要具備Symbol.iterator屬性,就能夠認爲是「可遍歷的」(iterable)。
Symbol.iterator屬性自己是一個函數,就是當前數據結構默認的遍歷器生成函數。執行這個函數,就會返回一個遍歷器。屬性名Symbol.iterator,它是一個表達式,返回Symbol對象的iterator屬性,這是一個預約義好的、類型爲 Symbol 的特殊值,因此要放在方括號內。對象
const obj={ [Symbol.iterator]: function() { return { next: function() { return { value: 1, done: true } } } } } obj[Symbol.iterator]().next(); // {value: 1, done: true}
上面代碼,obj具備Symbol.iterator屬性,是可遍歷的。執行這個屬性,會返回一個遍歷器對象。該對象的根本特徵就是具備next方法。每次調用next方法,都會返回一個表明當前成員的信息對象,具備value和done兩個屬性。
Array,Map,Set,String,TypedArray,函數的arguments對象,NodeList對象都具備Iterator接口。能夠被for...of遍歷。
注意: 對象(Object)沒有默認部署 Iterator 接口。索引
let values = [1, 2, 3]; for (let num of values) { console.log(num); // 1 2 3 }
for...of首先調用values數組的Symbol.iterator的方法,獲取一個迭代器。而後iterator.next()被調用,迭代器的value屬性被讀出並放入了num變量。num 變量的值開始爲 1 ,接下來是2,最後變成 3 。當結果對象的done變成true,循環就退出了。接口
上例的代碼也可採用下面的方法:
let values = [1, 2, 3]; let iter = values[Symbol.iterator](); iter.next(); // {value: 1, done: false} iter.next(); // {value: 2, done: false} iter.next(); // {value: 3, done: false} iter.next(); // {value: undefined, done: true}
ES5中有for...in遍歷對象,那麼for...in和for...of有什麼區別呢?
for ... in循環因爲歷史遺留問題,它遍歷的其實是對象的屬性名稱。一個Array數組實際上也是一個對象,它的每一個元素的索引被視爲一個屬性。當咱們手動給Array對象添加了額外的屬性後,for ... in循環將帶來意想不到的意外效果:
var a = ['A', 'B', 'C']; a.name = 'Hello'; for (var x in a) { console.log(x); // '0', '1', '2', 'name' }
採用for...of的寫法
var a = ['A', 'B', 'C']; a.name = 'Hello'; for (var x of a) { console.log(x); // 'A', 'B', 'C' }
結論:for...in遍歷的實際是key,而for...of遍歷的是value。
let colors = [ "red", "green", "blue" ]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ES6"); data.set("format", "ebook"); for (let entry of colors.entries()) { console.log(entry); } for (let entry of tracking.entries()) { console.log(entry); } for (let entry of data.entries()) { console.log(entry); }
以上代碼輸出結果:
[0, "red"] [1, "green"] [2, "blue"] [1234, 1234] [5678, 5678] [9012, 9012] ["title", "Understanding ES6"] ["format", "ebook"]
注意:數組不支持values()
let colors = [ "red", "green", "blue" ]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ES6"); data.set("format", "ebook"); for (let value of colors.values()) { console.log(value); } for (let value of tracking.values()) { console.log(value); } for (let value of data.values()) { console.log(value); }
以上代碼輸出結果:
TypeError: colors.values(...)[Symbol.iterator] is not a function 1234 5678 9012 "Understanding ES6" "ebook"
let colors = [ "red", "green", "blue" ]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ES6"); data.set("format", "ebook"); for (let key of colors.keys()) { console.log(key); } for (let key of tracking.keys()) { console.log(key); } for (let key of data.keys()) { console.log(key); }
以上代碼輸出結果:
0 1 2 1234 5678 9012 "title" "format"