摘要:由于中引入了許多數(shù)據(jù)結(jié)構(gòu)算上原有的包括等等數(shù)組需要一個東西來管理他們這就是遍歷器。數(shù)組默認遍歷器遍歷值相當于依次輸出依次輸出依次輸出依次輸出不難看出默認得到值而只能得到索引。即遍歷器的本質(zhì)就是一個指針。
由于 ES6 中引入了許多數(shù)據(jù)結(jié)構(gòu), 算上原有的包括Object, Array, TypedArray, DataView, buffer, Map, WeakMap, Set, WeakSet等等, 數(shù)組需要一個東西來管理他們, 這就是遍歷器(iterator)。
for...of遍歷器調(diào)用通常使用 for...of 循環(huán), for...of 可以遍歷具有 iterator 的對象, ES6中默認只有數(shù)組, Set, Map, String, Generator和一些類數(shù)組對象(arguments, DOM NodeList)帶有遍歷器, 其他的數(shù)據(jù)結(jié)構(gòu)需要自己定義遍歷器。
數(shù)組
默認 for...of 遍歷器遍歷值
var arr = ["red", "green", "blue"]; for(let v of arr){ //相當于 for(let i in arr.values()) console.log(v); //依次輸出 "red", "green", "blue" } for(let i in arr){ console.log(i); //依次輸出 0, 1, 2 } for(let [key, value] of arr.entries()){ console.log(key + ": " + value); //依次輸出 0: "red", 1: "green", 2: blue" } for(let key of arr.keys()){ console.log(key); //依次輸出 0, 1, 2 }
不難看出 for...of 默認得到值, 而 for...in 只能得到索引。當然數(shù)組的 for...of 只返回數(shù)字索引的屬性, 而 for...in 沒有限制:
var arr = ["red", "green", "blue"]; arr.name = "color"; for(let v of arr){ console.log(v); //依次輸出 "red", "green", "blue" } for(let i in arr){ console.log(arr[i]); //依次輸出 "red", "green", "blue", "color" }
Set
默認 for...of 遍歷器遍歷值
var set = new Set(["red", "green", "blue"]); for(let v of set){ //相當于 for(let i in arr.values()) console.log(v); //依次輸出 "red", "green", "blue" } for(let [key, value] of set.entries()){ console.log(key + ": " + value); //依次輸出 "red: red", "green: green", "blue: blue" } for(let key of set.keys()){ console.log(key); //依次輸出 "red", "green", "blue" }
map
默認 for...of 遍歷器遍歷鍵值對
var map = new Map(); map.set("red", "#ff0000"); map.set("green", "#00ff00"); map.set("blue", "#0000ff"); for(let [key, value] of map){ //相當于 for(let i in arr.entries()) console.log(key + ": " + value); //依次輸出 "red: #ff0000", "green: #00ff00", "blue: #0000ff" } for(let value of map.values()){ console.log(value); //次輸出 "#ff0000", "#00ff00", "#0000ff" } for(let key of map.keys()){ console.log(key); //次輸出 "red", "green", "blue" }
字符串
for...of可以很好的處理區(qū)分32位 Unicode 字符串
var str = "Hello"; for(let v of str){ console.log(v); //依次輸出 "H", "e", "l", "l", "o" }
類數(shù)組對象
// DOM NodeList var lis = document.getElementById("li"); for(let li of lis){ console.log(li.innerHTML); //遍歷每個節(jié)點 } //arguments function fun(){ for(let arg of arguments){ console.log(arg); //遍歷每個參數(shù) } }
不是所有類數(shù)組對象都有 iterator, 如果沒有, 可以先用Array.from()進行轉(zhuǎn)換:
var o = {0: "red", 1: "green", 2: "blue", length: 3}; var o_arr = Array.from(o); for(let v of o_arr){ console.log(v); //依次輸出 "red", "green", "blue" }
技巧1: 添加以下代碼, 使 for...of 可以遍歷 jquery 對象:
$.fn[Symbol.iterator] = [][Symbol.iterator];
技巧2: 利用 Generator 重新包裝對象:
function* entries(obj){ for(let key of Object.keys(obj)){ yield [key, obj[key]]; } } var obj = { red: "#ff0000", green: "#00ff00", blue: "#0000ff" }; for(let [key, value] of entries(obj)){ console.log(`${key}: ${value}`); //依次輸出 "red: #ff0000", "green: #00ff00", "blue: #0000ff" }幾種遍歷方法的比較
for 循環(huán): 書寫比較麻煩
forEach方法: 無法終止遍歷
for...in: 僅遍歷索引, 使用不便捷; 會遍歷原型鏈上的屬性, 不安全; 會遍歷非數(shù)字索引的數(shù)組屬性;
for...of:
iterator 與 [Symbol.iterator]iterator 遍歷過程是這樣的:
創(chuàng)建一個指針對象, 指向當前數(shù)據(jù)結(jié)構(gòu)的起始位置。即遍歷器的本質(zhì)就是一個指針。
調(diào)用一次指針的 next 方法, 指針指向第一數(shù)據(jù)成員。之后每次調(diào)用 next 方法都會將之后向后移動一個數(shù)據(jù)。
知道遍歷結(jié)束。
我們實現(xiàn)一個數(shù)組的遍歷器試試:
var arr = [1, 3, 6, 5, 2]; var it = makeIterator(arr); console.log(it.next()); //Object {value: 1, done: false} console.log(it.next()); //Object {value: 3, done: false} console.log(it.next()); //Object {value: 6, done: false} console.log(it.next()); //Object {value: 5, done: false} console.log(it.next()); //Object {value: 2, done: false} console.log(it.next()); //Object {value: undefined, done: true} function makeIterator(arr){ var nextIndex = 0; return { next: function(){ return nextIndex < arr.length ? {value: arr[nextIndex++], done: false} : {value: undefined, done: true} } }; }
由這個例子我們可以看出以下幾點:
迭代器具有 next() 方法, 用來獲取下一元素
next() 方法具有返回值, 返回一個對象, 對象 value 屬性代表下一個值, done 屬性表示是否遍歷是否結(jié)束
如果一個數(shù)據(jù)結(jié)構(gòu)本身不具備遍歷器, 或者自帶的遍歷器不符合使用要求, 請按此例格式自定義一個遍歷器。
其實一個 id 生成器就很類似一個遍歷器:
function idGen(){ var id = 0; return { next: function(){ return id++; } }; } var id = idGen(); console.log(id.next()); //0 console.log(id.next()); //1 console.log(id.next()); //2 //...
對于大多數(shù)數(shù)據(jù)結(jié)構(gòu), 我們不需要再像這樣寫遍歷器函數(shù)了。因為他們已經(jīng)有遍歷器函數(shù)[Symbol.iterator], 比如Array.prototype[Symbol.iterator] 是數(shù)組結(jié)構(gòu)的默認遍歷器。
下面定義一個不完整(僅包含add()方法)的鏈表結(jié)構(gòu)的實例:
function Node(value){ this.value = value; this.next = null; } function LinkedList(LLName){ this.head = new Node(LLName); this.tail = this.head; } var proto = { add: function(value){ var newNode = new Node(value); this.tail = this.tail.next = newNode; return this; } } LinkedList.prototype = proto; LinkedList.prototype.constructor = LinkedList; LinkedList.prototype[Symbol.iterator] = function(){ var cur = this.head; var curValue; return { next: function(){ if(cur !== null){ curValue = cur.value; cur = cur.next; return {value: curValue, done: false} } else { return {value: undefined, done: true} } } }; } var ll = new LinkedList("prime"); ll.add(1).add(2).add(3).add(5).add(7).add(11); for(let val of ll){ console.log(val); //依次輸出 1, 2, 3, 5, 7, 11 }
注意, 如果遍歷器函數(shù)[Symbol.iterator]返回的不是如上例所示結(jié)構(gòu)的對象, 會報錯。
當然, 如果不不喜歡用for...of(應該鮮有這樣的人吧), 可以用 while 遍歷:
var arr = [1, 2, 3, 5, 7]; var it = arr[Symbol.iterator]; var cur = it.next(); while(!cur.done){ console.log(cur.value); cur = it.next(); }
以下操作會在內(nèi)部調(diào)用相應的 iterator:
數(shù)組的解構(gòu)賦值
展開運算符
yield* 后面帶有一個可遍歷結(jié)構(gòu)
for...of
Array.from() 將類數(shù)組對象轉(zhuǎn)換為數(shù)組
Map(), Set(), WeakMap(), WeakSet() 等構(gòu)造函數(shù)傳輸初始參數(shù)時
Promise.all()
Promise.race()
Generator 與遍歷器iterator 使用 Generator 實現(xiàn)會更簡單:
var it = {}; it[Symbol.iterator] = function* (){ var a = 1, b = 1; var n = 10; while(n){ yield a; [a, b] = [b, a + b]; n--; } } console.log([...it]); //1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
當然, 以上代碼還可以這樣寫:
var it = { *[Symbol.iterator](){ var a = 1, b = 1; var n = 10; while(n){ yield a; [a, b] = [b, a + b]; n--; } } } console.log([...it]); //[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]遍歷器對象的其他方法
以上的遍歷器對象只提到了 next() 方法, 其實遍歷器還有 throw() 方法和 return() 方法:
如果遍歷終止(break, continue, return或者出錯), 會調(diào)用 return() 方法
Generator 返回的遍歷器對象具throw() 方法, 一般的遍歷器用不到這個方法。具體在 Generator 中解釋。
function readlineSync(file){ return { next(){ if(file.isAtEndOfFile()){ file.close(); return {done: true}; } }, return(){ file.close(); return {done: true}; } } }
上面實現(xiàn)了一個讀取文件內(nèi)數(shù)據(jù)的函數(shù), 當讀取到文件結(jié)尾跳出循環(huán), 但是當循環(huán)跳出后, 需要做一些事情(關(guān)閉文件), 以防內(nèi)存泄露。這個和 C++ 中的析構(gòu)函數(shù)十分類似, 后者是在對象刪除后做一些釋放內(nèi)存的工作, 防止內(nèi)存泄露。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/97443.html
摘要:函數(shù)可以沒有返回值,此時它依然返回一個并且在調(diào)用方法時一次行執(zhí)行完函數(shù)內(nèi)全部代碼,返回。將一個可遍歷結(jié)構(gòu)解構(gòu),并逐一返回其中的數(shù)據(jù)。 Generator Generator 函數(shù)是 es6 中的新的異步編程解決方案,本節(jié)僅討論 Generator 函數(shù)本身,異步編程放在后面的部分。Generator 函數(shù)之前也提到過,描述內(nèi)部封裝的多個狀態(tài),類似一個狀態(tài)機,當然也是很好的 iterat...
摘要:筆記和和是塊作用域的,是聲明常量用的。一個對象如果要有可被循環(huán)調(diào)用的接口,就必須在的屬性上部署遍歷器生成方法原型鏈上的對象具有該方法也可。這種方式會訪問注冊表,其中存儲了已經(jīng)存在的一系列。這種方式與通過定義的獨立不同,注冊表中的是共享的。 ECMAScript6 筆記 let 和 const let和const是塊作用域的 ,const是聲明常量用的。 {let a = 10;} a ...
摘要:迭代器要說生成器,必須首先說迭代器區(qū)分與講到迭代器,就需要區(qū)別幾個概念看著都差不多,其實不然。比如常見就是與分離實現(xiàn)的本身是可迭代對象,但不是迭代器,類似與但是又不同。 2016.3.10關(guān)于例子解釋的補充更新 源自我的博客 例子 老規(guī)矩,先上一個代碼: def add(s, x): return s + x def gen(): for i in range(...
摘要:來說說迭代器和生成器,還有可迭代對象和生成器表達式。有點繞是不是,其實,一般只要知道可迭代對象以及它是如何實現(xiàn)的就行了,中常常用生成器來代替迭代器,可以說,生成器就是迭代器。 來說說迭代器和生成器,還有可迭代對象和生成器表達式。 之前簡單的提到過,一個對象是可迭代的可以理解為能夠使用for循環(huán)。這樣說其實不太準確,某個對象可迭代是因為它內(nèi)部實現(xiàn)了$__iter__$這個特殊方法。比如在...
摘要:異步編程程序執(zhí)行分為同步和異步,如果程序每執(zhí)行一步都需要等待上一步完成才能開始,此所謂同步。因此異步編程十分重要。 異步編程 程序執(zhí)行分為同步和異步,如果程序每執(zhí)行一步都需要等待上一步完成才能開始,此所謂同步。如果程序在執(zhí)行一段代碼的同時可以去執(zhí)行另一段代碼,等到這段代碼執(zhí)行完畢再吧結(jié)果交給另一段代碼,此所謂異步。比如我們需要請求一個網(wǎng)絡資源,由于網(wǎng)速比較慢,同步編程就意味著用戶必須等...
閱讀 3271·2021-11-23 09:51
閱讀 3732·2021-09-22 15:35
閱讀 3720·2021-09-22 10:02
閱讀 3031·2021-08-30 09:49
閱讀 590·2021-08-05 10:01
閱讀 3472·2019-08-30 15:54
閱讀 1729·2019-08-30 15:53
閱讀 3617·2019-08-29 16:27