ES6系列之迭代器與foro_第1頁
ES6系列之迭代器與foro_第2頁
ES6系列之迭代器與foro_第3頁
ES6系列之迭代器與foro_第4頁
ES6系列之迭代器與foro_第5頁
已閱讀5頁,還剩12頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

起源

一段標(biāo)準(zhǔn)的for循環(huán)代碼:

varcolors=["red","blue11];

for(vari=O>/e八=colons.length;i</c八;i++){

conso/e」og(co/od[]);

)

看著很簡單,但是再回顧這段代碼,實際上我們僅僅是需要數(shù)組中元素的值,但

是卻需要提前獲取數(shù)組長度,聲明索引變量等,尤其當(dāng)多個循環(huán)嵌套的時候,更

需要使用多個索引變量,代碼的復(fù)雜度就會大大增加,比如我們使用雙重循環(huán)進(jìn)

行去重:

Functionui^ique(array){

varres=[];

for(vari=O,arrayLeia=array.length;i<arrayLM;i++){

for(varj=O,resLe八=八gtk;j<resLen;j++){

if(arrayfi]===resfj]){

break)

}

}

if(j===rcsLc八)(

res.pus^arrayli]');

}

]

匕血巾res;

)

為了消除這種復(fù)雜度以及減少循環(huán)中的錯誤(比如錯誤使用其他循環(huán)中的變量),

ES6提供了迭代器和forof循環(huán)共同解決這個問題。

迭代器

所謂迭代器,其實就是一個具有next()方法的對象,每次調(diào)用next()都會返

回一個結(jié)果對象,該結(jié)果對象有兩個屬性,value表示當(dāng)前的值,done表示遍

歷是否結(jié)束。

我們直接用ES5的語法創(chuàng)建一個迭代器:

fiA八ctioncreateIteratoitems){

vari=O;

return(

Mxt:fuMtioi^O{

vardoM=i>=length;

varvalue=IdoM?辿35口'+":u八defined;

return(

doM:doM,

value:value

};

)

};

)

//iterator就是個迭代器對象item,"=c%比cites亡。?[工2>3]);

cok\$ol^log(iterator.Mxt()');//{doM:false,value:(}coiasole.log(iterator.MXt('))://{doM:

false,value:2}cok\sole.log(iterator.iaext());//{doM:fake,value:

3}coiasole.log(iterator.Mxt(y);//{doM:true,value:〃八de行八cd)

forof

除了迭代器之外,我們還需要一個可以遍歷迭代器對象的方式,ES6提供了for

of語句,我們直接用forof遍歷一下我們上節(jié)生成的遍歷器對象試試:

variterator=cre.atelterator([i-,2,3J);

For(letvalueofiterator){

co^.sole..log(value);

}

結(jié)果報錯TgpeError:iteratorisnotiterab/e,表明我們生成的iterator對象并不是

iterable(可遍歷的)。

那什么才是可遍歷的呢?

其實一種數(shù)據(jù)結(jié)構(gòu)只要部署了Iterator接口,我們就稱這種數(shù)據(jù)結(jié)構(gòu)是"可遍歷

的"(iterable)。

ES6規(guī)定,默認(rèn)的Iterator接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性,或

者說,一個數(shù)據(jù)結(jié)構(gòu)只要具有SymboLiterator屬性,就可以認(rèn)為是‘可遍歷的”

(iterable)。

舉個例子:

coMobj={

value:1

);

For(valueofobj){

co^ole.log(value);

]

//TypeError:iteratoris八。titerable

我們直接forof遍歷一個對象,會報錯,然而如果我們給該對象添加

SymboLiterator屬性:

constobj={

value:1

};

obj[Syi^bol.iterator]=Fn八cti。八0(

returncreatetteratordlj2,3]);

for(valueofobj){

co^ole.log(value);

}

//1〃2〃3

由此,我們也可以發(fā)現(xiàn)forof遍歷的其實是對象的SymboLiterator屬性。

默認(rèn)可遍歷對象

然而如果我們直接遍歷一個數(shù)組對象:

coi^stcolors=["red1^"greeia1^"blue"];

for(letcolorofcolors){

conso/e」og(co/oK);

}

//red//g%e"/blue

盡管我們沒有手動添加SymboLiterator屬性,還是可以遍歷成功,這是因為

ES6默認(rèn)部署了SymboLiterator屬性,當(dāng)然我們也可以手動修改這個屬性:

vavcolors=["red","勿

colors[Sykv\bol.iterator]=fu八cti。八0(

returncreatelteratord^j2,3]);

for(letcolorofcolors}{

co八os/e」og(co/or);

)

//1//2〃3

除了數(shù)組之外,還有一些數(shù)據(jù)結(jié)構(gòu)默認(rèn)部署了SymboLiterator屬性。

所以for...of循環(huán)可以使用的范圍包括:

1.數(shù)組

2.Set

3.Map

4.類數(shù)組對象,如arguments對象、DOMNodeList對象

5.Generator對象

6,字符串

模擬實現(xiàn)forof

其實模擬實現(xiàn)forof也比較簡單,基本就是通過Symbol.iterator屬性獲取迭

代器對象,然后使用while遍歷一下:

八ctio八forOf(obj,cb){

letiterable,yesbdt;

if(typeofobj[Sykv\bol.iterator]/=="futaction")

thrownewTypeErrorfresult+“is八。2iterablen);

if(typeofch!==throwMWTgpcE"叭“cbmustbecallable11);

iterable=obj[Sykv\bol.iterator]();

result=iterable.MxtO;

while(frcsult.doM){

cb(result.value);

result=iterable.MXtO;

]

內(nèi)建迭代器

為了更好的訪問對象中的內(nèi)容,比如有的時候我們僅需要數(shù)組中的值,但有的時

候不僅需要使用值還需要使用索引,ES6為數(shù)組、M叩、Set集合內(nèi)建了以下三

種迭代器:

1.entries()返回一個遍歷器對象,用來遍歷[鍵名,鍵值]組成的數(shù)組。對于

數(shù)組,鍵名就是索引值。

2.keys()返回一個遍歷器對象,用來遍歷所有的鍵名。

3.values()返回一個遍歷器對象,用來遍歷所有的鍵值。

以數(shù)組為例:

varcolors-[〃匕力,"gree"一例ue”];

For(letindexofco/od.kcgs。){

co^ole.log(ik\dex);

)

//O//2〃2

for(letcolorofcolors.values()){

co八so/e」og(co/oK);

}

//%d〃grec八〃blue

for(letofco/od.cMricsO){

co八S0/c」og(7±e&);

]

//[O,"red"]//[1,"green"]//[2,"blue,"]

Map類型與數(shù)組類似,但是對于Set類型需要注意以下:

,,U

varcolors=MWSet(["redJ"gree^'jblue"]);

for(letindexofco/od.kcgs。){

co八so/e」og(i八dex);

)

//red//gree八〃blue

for(letcolorofcolors.valu^O){

coi^sole.log(color);

]

//red//gree八〃blue

for(letofCO/OHS.C*也s。){

co八so/e」og(itcd);

)

//[Wed",—"]//["grec八","gwe八"]//["blue11,ub[iAe.u]

Set類型的keys()和valuesQ返回的是相同的迭代器,這也意味著在Set這

種數(shù)據(jù)結(jié)構(gòu)中鍵名與鍵值相同。

而且每個集合類型都有一個默認(rèn)的迭代器,在for-of循環(huán)中,如果沒有顯式指

定則使用默認(rèn)的迭代器。數(shù)組和Set集合的默認(rèn)迭代器是valuesQ方法,Map

集合的默認(rèn)迭代器是entriesQ方法。

這也就是為什么直接forof遍歷Set和M叩數(shù)據(jù)結(jié)構(gòu),會有不同的數(shù)據(jù)結(jié)構(gòu)

返回:

constvaluer=newSet(口,2>3]);

for(letvalueofvalues}{

coi^sole.log(value);

]

//1//2〃3

constvalues=MWMapd^'keyl","value^"^["keg2"JV〃Me2"JD;F"(麻valueofvaliAes){

co^ole.log(value);

}

1,,,,un

//[''keyl',"valued"]//[key2JvalueZ]

遍歷Map數(shù)據(jù)結(jié)構(gòu)的時候可以順便結(jié)合解構(gòu)賦值:

,,,,n

constvaluer=newMap(l[keyl"Jvaluel],["keg2"J"Hue2"JJ);

for(let[key,value]ofvalues}{

con$ol^.log(key+":"+value);

}

//keglvabc工//key2.:value2

Babel是如何編譯forof的

我們可以在Babel的Tryitout中查看編譯的結(jié)果:

,,

coi^stcolors=MWSet(["redJ"blue"]);

for(letcolorofcolors){

coy^ole.log(color);

}

對于這樣一段代碼,編譯的結(jié)果如下:

“usestrict";

varcolors=MWSet(["red","g%e八、%山e〃J);

varJteratorNor^alCoi^pletioia=tru^var^didlteratorError=false;varJteratorError=

undefined;

try(

for(

vavJterator=colorslSyi^bol.iteratorJOj_$tcp;

!(_iteratorMon^alCo^pletioi^=(_$tep=_iterator?.八cx±0).do八e);

JteratorNor^alCokv\pletioki=true.

){

varcolor=_step.value)

co^ole.log(colo^)

}

}catch(err){

_didlteratorEr^or=true;

Jter^torError=err;

}finally{

try(

if(!jteratorNori^alCokv\pletion.&&Jterator.retum){

Jterator.retum();

)

}finally{

if(_didlteratorError){

throwjtemtorHrror;

)

)

)

至少由編譯的結(jié)果可以看出,使用f*of循環(huán)的背后,還是會使用

Symbol.iterator接口。

而這段編譯的代碼稍微復(fù)雜的地方有兩段,一段是for循環(huán)這里:

for(

varJte^ato^=colors[Sy^bol.iterator](),_$tep;

!(JteratorNo^i^alCo^pletioi^=(_$tep=」'±CK〃tor*.八ex±()).do八e);

JteratorNormaiCo^vxpletioia=true

)(

vav-color-_$tep.vatue;

console.log(color);

)

跟標(biāo)準(zhǔn)的for循環(huán)寫法有些差別,我們看下for語句的語法:

for(initialize;test;mcremen.t)statement;

initialize,test和increment三個表達(dá)式之間用分號分割,它們分別負(fù)責(zé)仞始化

操作、循環(huán)條件判斷方口計數(shù)器變量的更新。

for語句其實就相當(dāng)于:

i八itia(ize;whi(e(test){

merecent;

]

代碼的邏輯為:先進(jìn)行初始化,然后每次循環(huán)執(zhí)行之前會執(zhí)行test表達(dá)式,并

判斷表達(dá)式的結(jié)果來決定是否執(zhí)行循環(huán)體,如果test計算結(jié)果為真值,則執(zhí)行

循環(huán)體中的statemento最后,執(zhí)行increment表達(dá)式。

而且值得注意的是,其實for循環(huán)中的三個表達(dá)式中任意一個都可以被忽略,

不過分號還是要寫的。

比如土,不過這就是一個死循環(huán)……

比如:

vari-O,

他八=colors.leiagtk;fo^(;i<他八;i++)(

coi^sole.log(colors[i]);

]

又比如:

vari-

加八=co/。%.3Vg仇For*(;i<加八;){

i++;

)

然后我們再來看Babel編譯的這個for循環(huán)表達(dá)式:

for(

variterator=colorslSyi^bol.iteratorJO,_$tep;

((JteratorNor^,alCoiM.pletioi^=(_$tep=_iterator.MKt(y).doM);

JteratorNori^alCo^pletioi^=true

)(

varcolor=jtepvaliA。;

coi^sole.log(color);

)

用while的寫法相當(dāng)于:

varJte^ator=colors[Syi^bo(.iterator](),

_$tep;while-(!(」七。戊。小"陋址0呻怙七沁八=(_$tep=_iterator.MXt(y).doi^e)){

varcolor=_$tep.va(ue;

co^sole.log(color);

_jteratorNov'w\alCow\pletio^-true;

)

是不是就好懂/很多呢,然后你就會發(fā)現(xiàn),其實亡OHNOKHAHCO叫?/etio八=true這

句是完全沒有必要的……

另外一段稍微復(fù)雜的代碼是:

try(

}catch(err){

}finally(

try(

if(!_iteratorNori^alCoi^pletioi^&&Jterator.retum){

Jterator.retum();

)

}finally{

)

)

因為_iteratorNorkv\alCokv\pletio^.=(jtep=Jterator.MxtO).doM,所以

JteratorNormalCompletion表示的就是是否完成了一次完整的迭代過程,如果

沒有正常的迭代完成,并且迭代器有return方法時,就會執(zhí)行該方法。

而之所以這么做,就要提到迭代器的return方法。

引用阮一峰老師的ECMAScript6入門:

遍歷器對象除了具有next方法,還可以具有return方法和

throw方法。如果你自己寫遍歷器對象生成函數(shù),那么next方法

是必須部署的,return方法和throw方法是否部署是可選的。

return方法的使用場合是,如果for...of循環(huán)提前退出(通常是因

為出錯,或者有break語句或continue語句),就會調(diào)用return

方法。如果一個對象在完成遍歷前,需要清理或釋放資源,就可以

部署return方法。

我們可以舉個例子:

fuMtioiacreateIterator(items){

vari-O\

return{

next:ftmc力'。八0(

vavdoM=i>=iteMS.Ie八gth;

varvalue=IdoM?:u八defined;

return(

doM:doM,

value:value

);

h

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論