JavaScript詳解類數(shù)組與可迭代對(duì)象的實(shí)現(xiàn)原理
可迭代對(duì)象(Iterable object)
數(shù)組是一個(gè)特殊的對(duì)象,它和普通對(duì)象的區(qū)別不僅僅在于元素的順序訪問(wèn)、存儲(chǔ)。另外一個(gè)重要的區(qū)別是:數(shù)組是可迭代的,也就是可以使用for ... of
語(yǔ)句訪問(wèn)(迭代)所有的元素。
我們可以簡(jiǎn)單的做一個(gè)小實(shí)驗(yàn):
let arr = [1,2,3,4,5] for(let val of arr){ console.log(val) }
代碼執(zhí)行結(jié)果:
以上代碼就簡(jiǎn)單的使用了數(shù)組的迭代特性,我們?cè)谠L問(wèn)數(shù)組元素的時(shí)候,不必使用元素的下標(biāo)。
如果我們對(duì)一個(gè)普通對(duì)象使用for ... of
語(yǔ)句會(huì)發(fā)生什么呢?
let obj = { name:'xiaoming', age:12, } for(let para of obj){ //代碼會(huì)報(bào)錯(cuò) console.log(para) }
執(zhí)行效果如下:
這就證明普通的對(duì)象和數(shù)組之間還有一個(gè)可迭代的差距,我們稱具備迭代功能的對(duì)象為可迭代對(duì)象。
Symbol.iterator
如果我們希望一個(gè)對(duì)象可以迭代,必須為對(duì)象添加一個(gè)名為Symbol.iterator
的方法(一個(gè)專門(mén)使對(duì)象可迭代的內(nèi)建Symbol
)。
方法作用包括:
- 當(dāng)使用
for ... of
循環(huán)迭代對(duì)象時(shí),就會(huì)調(diào)用Symbol.iterator
方法,這個(gè)方法必須返回一個(gè)迭代器(一個(gè)有next()
方法的對(duì)象)。 - 得到迭代器后,
for ... of
會(huì)不斷的調(diào)用迭代器的next()
方法獲得下一個(gè)元素 next()
方法返回的內(nèi)容必須符合格式:{done:Boolean,value:any}
,當(dāng)done:true
時(shí),循環(huán)結(jié)束,否則value
就是下一個(gè)值。
迭代器:
迭代器是借鑒C++
等語(yǔ)言的概念,迭代器的原理就像指針一樣,它指向數(shù)據(jù)集合中的某個(gè)元素,你可以獲取它指向的元素,也可以移動(dòng)它以獲取其它元素。迭代器類似于數(shù)組中下標(biāo)的拓展,各種數(shù)據(jù)結(jié)構(gòu),如鏈表(List
)、集合(Set
)、映射(Map
)都有與之對(duì)應(yīng)的迭代器。
JS
中的迭代器是專門(mén)為了遍歷這一操作設(shè)計(jì)的。每次獲取到的迭代器總是初始指向第一個(gè)元素,并且迭代器只有next()
一種行為,直到獲取到數(shù)據(jù)集的最后一個(gè)元素。我們無(wú)法靈活移動(dòng)迭代器的位置,所以,迭代器的任務(wù),是按某種次序遍歷數(shù)據(jù)集中的元素。
實(shí)現(xiàn)一個(gè)可迭代對(duì)象:
let obj = { from:1, to:5, } obj[Symbol.iterator] = function(){ //返回一個(gè)迭代器 return { current:this.from, last:this.to, next(){ if(this.current<this.last){ return {done:false,value:this.current++} }else{ return {done:true}//迭代結(jié)束 } } } } for(let para of obj){ console.log(para) }
代碼執(zhí)行效果:
注意,以上對(duì)象雖然可以進(jìn)行迭代了,但是,迭代使用使用的材料并非對(duì)象,而是Symbol.iterator
返回的迭代器(也是一個(gè)對(duì)象)。
把對(duì)象本身構(gòu)造成迭代器
以上代碼構(gòu)造了一個(gè)內(nèi)建函數(shù)Symbol.iterator()
,這個(gè)函數(shù)返回了一個(gè)迭代器對(duì)象。我們還可以采用另外一種實(shí)現(xiàn)迭代器的方式:把對(duì)象本身做成迭代器:
let obj = { from:1, to:5, [Symbol.iterator](){ this.current = this.from; return this;//返回對(duì)象本身 }, next(){//給對(duì)象添加一個(gè)next方法 if(this.current<this.to){ return {done:false,value:this.current++} }else{ return {done:true} } } } for(let para of obj){ console.log(para) }
代碼執(zhí)行效果和上面的圖片展示相同。
這么做雖然代碼更加簡(jiǎn)潔了,但是由于并沒(méi)有新的可迭代對(duì)象產(chǎn)生,我們就沒(méi)有辦法同時(shí)執(zhí)行兩個(gè)for ... of
循環(huán)迭代同一個(gè)對(duì)象了,但是兩個(gè)并行的迭代在同一個(gè)對(duì)象上是非常罕見(jiàn)的。
我們可以總結(jié)可迭代對(duì)象的概念:
所謂可迭代對(duì)象,就是比普通對(duì)象多了一個(gè)名為Symbol.iterator
方法的普通對(duì)象,這個(gè)方法返回一個(gè)迭代器。
或者,一個(gè)具備Symbol.iterator
同時(shí)具備next
方法的對(duì)象也是一個(gè)可迭代的對(duì)象。
String也是可迭代的
數(shù)組和字符串都是可以迭代的,我們可以很方便的使用for...of
語(yǔ)句迭代數(shù)組中的字符元素:
let str = '123' for(let c of str){ console.log(c) }
這對(duì)于代理對(duì)(UTF-16
擴(kuò)展字符)同樣是有效的:
let str = '?????????????????????' for(let c of str){ console.log(c) }
執(zhí)行效果如下:
String的迭代器
并非只有for...of
語(yǔ)句能夠使用迭代器,我們還可以顯式的調(diào)用迭代器:
let str = '12345' let itr = str[Symbol.iterator]() while(true){ let result = itr.next() if(result.done)break; console.log(result.value) }
代碼執(zhí)行效果:
以上代碼執(zhí)行了遍歷字符串字符的操作,是不是覺(jué)得可迭代對(duì)象就沒(méi)有這么神秘了!
類數(shù)組對(duì)象和可迭代對(duì)象
類數(shù)組和可迭代在遍歷功能上非常相似,都可以方便的方式內(nèi)部元素,但是二者仍然有明顯的區(qū)別:
iterable
可迭代對(duì)象:實(shí)現(xiàn)了Symbol.iterator
的對(duì)象;array-like
類數(shù)組對(duì)象:具有數(shù)字索引,并且有length
屬性;
字符串就是一個(gè)即使類數(shù)組又是可迭代的對(duì)象。
可迭代和類數(shù)組對(duì)象通常都不是數(shù)組,如果我們想把一個(gè)可迭代或者類數(shù)組對(duì)象轉(zhuǎn)為數(shù)組,需要使用Array.from
方法。
Array.from
使用Array.from
將字符串轉(zhuǎn)為數(shù)組:
let str = '123' let arr = Array.from(str) console.log(arr)
代碼執(zhí)行效果如下:
把自定義的類數(shù)組對(duì)象轉(zhuǎn)為數(shù)組:
let obj = { 0:'0', 1:'1', 2:'2', length:3 } let arr = Array.from(obj) console.log(arr)
代碼執(zhí)行結(jié)果:
Array.from
的完整語(yǔ)法:
Array.from(obj[, mapFunc, thisArg])
mapFunc
方法會(huì)在生成數(shù)組之前對(duì)每個(gè)可迭代或類數(shù)組元素調(diào)用,如果mapFunc
是一個(gè)成員方法,可以使用thisArg
提供this
指針。
舉個(gè)例子:
let str = '12345' let arr = Array.from(str,itm=>+itm) console.log(arr)
代碼執(zhí)行結(jié)果:
這里通過(guò)映射函數(shù),將本應(yīng)該生成字符數(shù)組轉(zhuǎn)為數(shù)字?jǐn)?shù)組。
總結(jié)
- 可以使用
for...of
語(yǔ)法的對(duì)象被稱為可迭代對(duì)象 - 可迭代對(duì)象是在普通對(duì)象的基礎(chǔ)上實(shí)現(xiàn)了
Symbol.iterator
方法的對(duì)象 Symbol.iterator
方法返回了一個(gè)迭代器;- 迭代器包含一個(gè)
next
方法,該方法返回下一個(gè)元素的值; next
方法返回值需要滿足格式{done:Boolean,value:nextVal}
,當(dāng)done:true
時(shí),迭代結(jié)束Array.from
可以把類數(shù)組和可迭代對(duì)象轉(zhuǎn)為數(shù)組;
到此這篇關(guān)于JavaScript詳解類數(shù)組與可迭代對(duì)象的實(shí)現(xiàn)原理的文章就介紹到這了,更多相關(guān)JavaScript 類數(shù)組與可迭代對(duì)象內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript設(shè)計(jì)模式之中介者模式Mediator
這篇文章主要介紹了javascript設(shè)計(jì)模式之中介者模式Mediator,需要的朋友可以參考下2014-12-12javascript刪除option選項(xiàng)的多種方法總結(jié)
這篇文章主要是對(duì)javascript刪除option選項(xiàng)的多種方法進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-11-11前端使用crypto.js進(jìn)行加密的函數(shù)代碼
最近在使用Cookies加密保存數(shù)據(jù)的時(shí)候,接觸到crypto,使用還算簡(jiǎn)單,在這里記錄一下2020-08-08JS新包管理工具yarn和npm的對(duì)比與使用入門(mén)
在2016年10月11日f(shuō)acebook 公開(kāi)了新的javascript包管理工具 yarn, 用來(lái)替代目前被廣泛使用的npm(nodejs 自帶的包管理工具),本文將介紹yarn工具帶來(lái)的優(yōu)點(diǎn)和使用入門(mén),以及對(duì)比npm解決了什么問(wèn)題,帶來(lái)哪些便利。有需要的朋友們下面來(lái)一起看看吧。2016-12-12js DIV滾動(dòng)條隨機(jī)位置的設(shè)置技巧
剛才一個(gè)朋友告訴我他的blog友情鏈接太多了,所以把所有鏈接放到一個(gè)DIV中,加了個(gè)滾動(dòng)條,可是他又不想每次別人來(lái)看,看到的都是前面幾個(gè)鏈接,于是問(wèn)我有沒(méi)有什么辦法,想了一個(gè),呵呵,正好有個(gè)辦法2008-11-11JS驗(yàn)證控制輸入中英文字節(jié)長(zhǎng)度(input、textarea等)具體實(shí)例
JS驗(yàn)證控制輸入中英文字節(jié)長(zhǎng)度(input、textarea等)具體實(shí)例,需要的朋友可以參考一下2013-06-06Three.js如何用軌跡球插件(trackball)增加對(duì)模型的交互功能詳解
這篇文章主要給大家介紹了關(guān)于Three.js如何用軌跡球插件,也就是trackball增加對(duì)模型的交互功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-09-09