JavaScript 原有的表示「集合」的數據結構,主要是數組(Array)和對象(Object),ES6 又添加了Map和Set。這樣就須要一種統一的接口機制,來處理全部不一樣的數據結構。遍歷器(Iterator)就是這樣一種機制。它是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只要部署 Iterator 接口,就能夠完成遍歷操做(即依次處理該數據結構的全部成員)。html
let arr3 = [1, 2, 'kobe', true];
for(let i of arr3){
console.log(i); // 1 2 kobe true
}
複製代碼
let str = 'abcd';
for(let item of str){
console.log(item); // a b c d
}
複製代碼
function fun() {
for (let i of arguments) {
console.log(i) // 1 4 5
}
}
fun(1, 4, 5)
複製代碼
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
console.log(e);
}
// Gecko
// Trident
// Webkit
複製代碼
function myIterator(arr) {
let nextIndex = 0
return {
next: function() {
return nextIndex < arr.length
? { value: arr[nextIndex++], done: false }
: { value: undefined, value: true }
}
}
}
let arr = [1, 4, 'ads']// 準備一個數據
let iteratorObj = myIterator(arr)
console.log(iteratorObj.next()) // 全部的迭代器對象都擁有next()方法,會返回一個結果對象
console.log(iteratorObj.next())
console.log(iteratorObj.next())
console.log(iteratorObj.next())
複製代碼
① for of循環不支持遍歷普通對象前端
var obj = { a: 2, b: 3 }
for (let i of obj) {
console.log(i) // Uncaught TypeError: obj is not iterable
}
複製代碼
對象的Symbol.iterator屬性,指向該對象的默認遍歷器方法。當使用for of去遍歷某一個數據結構的時候,首先去找Symbol.iterator,找到了就去遍歷,沒有找到的話不能遍歷,提示Uncaught TypeError: XXX is not iterable
git
② 當使用擴展運算符(...)或者對數組和 Set 結構進行解構賦值時,會默認調用Symbol.iterator方法es6
let arr1 = [1,3]
let arr2 = [2,3,4,5]
arr2 = [1,...arr2,6]
console.log(arr2) // [1, 2, 3, 4, 5, 6]
複製代碼
function* generatorExample(){
console.log("開始執行")
yield 'hello';
yield 'generator';
}
// generatorExample()
// 這種調用方法Generator 函數並不會執行
let MG = generatorExample() // 返回指針對象
MG.next() //開始執行 {value: "hello", done: false}
複製代碼
Generator 函數是分段執行的,調用next方法函數內部邏輯開始執行,遇到yield表達式中止,返回{value: yield後的表達式結果/undefined, done: false/true}
,再次調用next方法會從上一次中止時的yield處開始,直到最後。github
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()// { value: 'hello', done: false }
hw.next()// { value: 'world', done: false }
hw.next()// { value: 'ending', done: true }
hw.next()// { value: undefined, done: true }
複製代碼
第一次調用,Generator 函數開始執行,直到遇到第一個yield表達式爲止。next方法返回一個對象,它的value屬性就是當前yield表達式的值hello,done屬性的值false,表示遍歷尚未結束。ajax
第二次調用,Generator 函數從上次yield表達式停下的地方,一直執行到下一個yield表達式。next方法返回的對象的value屬性就是當前yield表達式的值world,done屬性的值false,表示遍歷尚未結束。編程
第三次調用,Generator 函數從上次yield表達式停下的地方,一直執行到return語句(若是沒有return語句,就執行到函數結束)。next方法返回的對象的value屬性,就是緊跟在return語句後面的表達式的值(若是沒有return語句,則value屬性的值爲undefined),done屬性的值true,表示遍歷已經結束。數組
第四次調用,此時 Generator 函數已經運行完畢,next方法返回對象的value屬性爲undefined,done屬性爲true。之後再調用next方法,返回的都是這個值。bash
yield表達式自己沒有返回值,或者說老是返回undefined。next方法能夠帶一個參數,該參數就會被看成上一個yield表達式的返回值。數據結構
function* generatorExample () {
console.log('開始執行')
let result = yield 'hello'
console.log(result)
yield 'generator'
}
let MG = generatorExample()
MG.next()
MG.next()
// 開始執行
// undefined
// {value: "generator", done: false}
複製代碼
沒有傳值時result默認是undefined,接下來咱們向第二個next傳遞一個參數,看下輸出結果是啥?
function* generatorExample () {
console.log('開始執行')
let result = yield 'hello'
console.log(result)
yield 'generator'
}
let MG = generatorExample()
MG.next()
MG.next(11)
// 開始執行
// 11
// {value: "generator", done: false}
複製代碼
咱們上文中提到對象沒有iterator接口,用for...of遍歷時便會報錯。
let obj = { username: 'kobe', age: 39 }
for (let i of obj) {
console.log(i) // Uncaught TypeError: obj is not iterable
}
複製代碼
因爲 Generator 函數就是遍歷器生成函數,所以能夠把 Generator 賦值給對象的Symbol.iterator屬性,從而使得該對象具備 Iterator 接口。
let obj = { username: 'kobe', age: 39 }
obj[Symbol.iterator] = function* myTest() {
yield 1;
yield 2;
yield 3;
};
for (let i of obj) {
console.log(i) // 1 2 3
}
複製代碼
上面代碼中,Generator函數賦值給Symbol.iterator屬性,從而使得obj對象具備了 Iterator 接口,能夠被for of遍歷了。
function* sendXml() {
// url爲next傳參進來的數據
let url = yield getNews('http://localhost:3000/news?newsId=2');//獲取新聞內容
yield getNews(url);//獲取對應的新聞評論內容,只有先獲取新聞的數據拼湊成url,才能向後臺請求
}
function getNews(url) {
$.get(url, function (data) {
console.log(data);
let commentsUrl = data.commentsUrl;
let url = 'http://localhost:3000' + commentsUrl;
// 當獲取新聞內容成功,發送請求獲取對應的評論內容
// 調用next傳參會做爲上次暫停是yield的返回值
sx.next(url);
})
}
let sx = sendXml();// 發送請求獲取新聞內容
sx.next();
複製代碼
若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!