JavaScript中Iterator迭代器接口和循環(huán)
JavaScript的迭代器(Iterator)介紹
迭代器是數(shù)據(jù)結(jié)構(gòu)遍歷的一種機(jī)制(或者是什么我也不太懂的行業(yè)術(shù)語),為數(shù)據(jù)結(jié)構(gòu)定義了統(tǒng)一的遍歷規(guī)則。 迭代器(Iterator)主要是提供for...of
使用,或者說,數(shù)據(jù)結(jié)構(gòu)只有實(shí)現(xiàn)了迭代器(Iterator)接口才能使用for...of
進(jìn)行遍歷數(shù)據(jù),當(dāng)一種數(shù)據(jù)結(jié)構(gòu)沒有實(shí)現(xiàn)迭代器(Iterator)接口時(shí),去使用for...of
操作,就會(huì)被拋出異常Uncaught TypeError: xxx is not iterable
。
JavaScript的迭代器(Iterator)的接口規(guī)范和操作過程:
- 迭代器被調(diào)用時(shí),返回一個(gè)指針對(duì)象,指針對(duì)象中必須包含一個(gè)
next()
的方法,每次調(diào)用next()
方法,都會(huì)返回一個(gè)代表當(dāng)前成員的信息對(duì)象,具有value
和done
兩個(gè)屬性。value
可為任意數(shù)據(jù)類型,done
則是一個(gè)布爾類型,當(dāng)調(diào)用next
的方法時(shí)返回的對(duì)象中的done
屬性為false
時(shí),表示還可以繼續(xù)進(jìn)行遍歷,當(dāng)done
屬性為true
時(shí),表示遍歷結(jié)束(沒有的東西遍歷了)了。 - 迭代器(Iterator)對(duì)象的可選屬性
return()
方法和throw()
方法,也就是說當(dāng)我們要自己去實(shí)現(xiàn)迭代器(Iterator)的時(shí)候,迭代器里必須要有next()
方法,而return()
方法和throw()
是否要實(shí)現(xiàn)是可選的。而自己實(shí)現(xiàn)迭代器(Iterator)時(shí),不管是next()
、return()
還是throw()
方法必須有返回值并且是對(duì)象,否則進(jìn)行遍歷的時(shí)候會(huì)拋出異常Uncaught TypeError: Iterator result xxx is not an object
。 - 自己實(shí)現(xiàn)迭代器,只要給數(shù)據(jù)結(jié)構(gòu)或者對(duì)象添加
[Symbol.iterator]
屬性即可,其值必須是一個(gè)函數(shù),返回一個(gè)只針對(duì)象,需遵循第2點(diǎn)的規(guī)范。為什么必須是[Symbol.iterator]
的屬性名,因?yàn)镴avaScript的定義中,尋找遍歷器時(shí)就是用這個(gè)字段,這也是一個(gè)標(biāo)準(zhǔn)規(guī)范。
下面是自己實(shí)現(xiàn)迭代器的演示代碼:
const obj = {a: "age 18", b: 2}; // 實(shí)現(xiàn)迭代器 obj[Symbol.iterator] = function () { const keys = Object.keys(obj); let keyIndex = 0; return { next() { if (keys.length === 0 || keyIndex >= keys.length) { return { value: undefined, done: true } } const key = keys[keyIndex], value = [key, obj[key]]; keyIndex += 1; return { value, done: false } } }; } // 使用for...of進(jìn)行遍歷 for (let [key, value] of obj) { console.log(`${key}--${value}`) } // a--age 18 // b--2
返回參數(shù)簡寫,當(dāng)返回正常值的時(shí)候,done
字段可以省略,當(dāng)循環(huán)結(jié)束的時(shí)候,value
可以省略。但是注意不能兩個(gè)都不寫,不然會(huì)死循環(huán),而且必須要有條件結(jié)束的操作,不然也會(huì)死循環(huán),就像遞歸一樣,一定要有條件結(jié)束的操作
Number.prototype[Symbol.iterator] = function () { let that = +this, i = that < 0 ? that : 0; that = that < 0 ? 0 : that; return { next() { if (i <= that) { const value = i; i += 1; return { value }; } return { done: true }; } }; }; for (const item of 20) { console.log(item); } // 數(shù)組的擴(kuò)展運(yùn)算符也是調(diào)用迭代器的哦 console.log([...5]);// [0, 1, 2, 3, 4, 5]
迭代器的可選參數(shù)return()
和throw()
return()
方法是在遍歷中斷的時(shí)候會(huì)調(diào)用,如使用了break
關(guān)鍵字中斷或者拋出了異常都會(huì)調(diào)用這個(gè)方法。return()
方法必須有返回參數(shù)并且要求是object
類型的數(shù)據(jù),否則就會(huì)拋出異常Uncaught TypeError: Iterator result undefined is not an object
,至于object
里內(nèi)容要求是什么,我測了一下,毫無影響,返回空對(duì)象也沒問題。
const obj = { size: 5, [Symbol.iterator]() { return { // 這里用箭頭函數(shù)為的是可以直接使用this next: () => { if (this.size >= 0) { const value = this.size; this.size -= 1; return { value }; } return { done: true }; }, return() { console.log("中斷了"); return { done: true }; // 返回以下內(nèi)容照樣不會(huì)有問題,但是最好不這么操作,因?yàn)榇a具有語義化才能更好的閱讀 // return {}; // return new Date(); } }; } }; for (const item of obj) { if (item < 3) { break;// 中斷了 } console.log(item); }
throw()
方法在迭代器中基本用不到,而是配合Generator
使用,這里就不做過多的敘述。
原生具備 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)如下:
- Array
- Map
- Set
- String
- TypedArray
- 函數(shù)的 arguments 對(duì)象
- NodeList 對(duì)象
for...of循環(huán)與for...in循環(huán)
上面已經(jīng)詳細(xì)的說明了迭代器(Iterator)主要是提供for...of
循環(huán)使用,所以for...of
循環(huán)時(shí)調(diào)用的是迭代器(Iterator),而循環(huán)的值是由實(shí)現(xiàn)的迭代器(Iterator)而定,而for...in
循環(huán)是循環(huán)鍵值。
const arr = ["a", "b", "c"]; // 原生的數(shù)組迭代器(Iterator)的實(shí)現(xiàn)遍歷時(shí)返回的是每一個(gè)元素 for (const item of arr) { console.log(item); // a // b // c } // for...in 返回的是key,這里是數(shù)組,key就是索引 for (const key in arr) { console.log(key); // 0 // 1 // 2 }
還有一個(gè)更直觀的區(qū)別。for...of
只是根據(jù)迭代器(Iterator)實(shí)現(xiàn)的內(nèi)容返回結(jié)果,所以就不會(huì)遍歷不在范圍的東西,而for...in
會(huì)把所有的鍵遍歷出來。
const arr = ["a", "b", "c"]; arr.testValue = 1; for (const item of arr) { console.log(item); // a // b // c } for (const item in arr) { console.log(item); // 0 // 1 // 2 // testValue }
到此這篇關(guān)于JavaScript中Iterator迭代器接口與循環(huán)的文章就介紹到這了,更多相關(guān)JavaScript Iterator 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
webuploader實(shí)現(xiàn)上傳圖片到服務(wù)器功能
這篇文章主要為大家詳細(xì)介紹了webuploader實(shí)現(xiàn)上傳圖片到服務(wù)器功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08layui固定下拉框的顯示條數(shù)(有滾動(dòng)條)的方法
今天小編就為大家分享一篇layui固定下拉框的顯示條數(shù)(有滾動(dòng)條)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09javascript的parseFloat()方法精度問題探討
javascript中的parseFloat()方法,大家應(yīng)該不陌生吧,下面為大家介紹下其精度問題,感興趣的朋友不要錯(cuò)過2013-11-11JavaScript實(shí)現(xiàn)的浮動(dòng)層框架用法實(shí)例分析
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的浮動(dòng)層框架用法,以實(shí)例形式分析了JavaScript實(shí)現(xiàn)可關(guān)閉的半透明浮動(dòng)層相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10原生js實(shí)現(xiàn)簡單的Ripple按鈕實(shí)例代碼
本篇文章主要介紹了原生js實(shí)現(xiàn)簡單的Ripple按鈕實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03