摘要:遍歷器對(duì)象調(diào)用方法后,拋出的異常被函數(shù)體捕獲以后,會(huì)附帶執(zhí)行下一條語(yǔ)句。
iterator迭代器
在ES6之前遍歷數(shù)組的方法有以下四種:
// 第一種 for(var i = 0; i < array.length; i++){ console.log(array[i]) } // 第二種 array.forEach(function(item,index){ console.log(item) }) // 第三種 for(var index in array){ console.log(array[index]) } // 第四種 for(var value of array){ console.log(value) }
在上面的遍歷方式中,第二種方式有一種小缺陷,就是不能使用break語(yǔ)句中斷執(zhí)行,也不能使用return語(yǔ)句返回到外層函數(shù)。它會(huì)一直遍歷完數(shù)組的所有元素。第三種方式是一個(gè)更糟糕的方式,在遍歷過程中,賦值給index的不是number類型,而是字符串類型,for-in循環(huán)除了遍歷數(shù)組外,還會(huì)遍歷自定義屬性,甚至是遍歷出原型鏈上的屬性。并且for-in的遍歷順序不能得到保障。
第四種方法是ES6中新增的遍歷數(shù)組的方法,它可以正確響應(yīng)break、continue和return語(yǔ)句,for-in語(yǔ)句除了能遍歷數(shù)組外,還能遍歷類數(shù)組對(duì)象,如DOM的NodeList對(duì)象,arguments對(duì)象,也能遍歷字符串、Set對(duì)象、Map對(duì)象。
for-of循環(huán)語(yǔ)句能夠遍歷各種集合的。是因?yàn)檫@些對(duì)象都有一個(gè)迭代器的方法,迭代器(Iterator)是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機(jī)制,任何數(shù)據(jù)結(jié)構(gòu)只要部署了iterator接口,就可以完成遍歷操作。比如下面這種情況:
let obj = { data:["hello","world"], [Symbol.iterator](){ const _self = this let index = 0 return { next(){ if(index < _self.data.length){ return {value:_self.data[index++],done:false} }else{ return {value:undefined,done:true} } } } } } for(var value of obj){ console.log(value) // 輸出 hello world }
迭代器也可以直接使用Array默認(rèn)的iterator。
// 也可以直接使用Array的迭代器 let newObj = { 0:"a", 1:"b", 2:"c", [Symbol.iterator]:Array.prototype[Symbol.iterator] } for(var value of newObj){ console.log(value) // 輸出 a b c }
for-of循環(huán)語(yǔ)句其實(shí)是調(diào)用遍歷對(duì)象的[Symbol.iterator]方法,該方法返回一個(gè)iterator,里面有一個(gè)next方法,for循環(huán)會(huì)不斷調(diào)用這個(gè)iterator.next方法來獲取下一個(gè)值,直到返回值中的done屬性為ture時(shí)結(jié)束循環(huán)。除了添加iterator外還可以使用yield實(shí)現(xiàn)循環(huán):
let obj = { [Symbol.iterator]: function* (){ for(var i = 0; i < 100; i++){ yield i } } } for(var value of obj){ console.log(value) }iterator的遍歷過程
創(chuàng)建一個(gè)指針對(duì)象,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置,也就是說,遍歷器對(duì)象的本質(zhì)就是一個(gè)指針對(duì)象。
第一次調(diào)用指針對(duì)象的next方法,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個(gè)成員。
不斷調(diào)用指針對(duì)象的next方法,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置。
當(dāng)使用for-of循環(huán)遍歷某個(gè)數(shù)據(jù)結(jié)構(gòu)時(shí),該循環(huán)會(huì)自動(dòng)去尋找iterator接口。只要一個(gè)對(duì)象含有iterator接口,那么該對(duì)象就可以被遍歷。
使用iterator的場(chǎng)景解構(gòu)賦值
let arr = [1,2,3,5] let [first,...second] = arr
擴(kuò)展運(yùn)算符
var str = "hello" [...str] // ["h","e","l","l","o"]
yield*
yield*后面跟的是一個(gè)可遍歷的結(jié)構(gòu),它就會(huì)調(diào)用該結(jié)構(gòu)的遍歷器接口。
let generator = function* (){ yield* [2,3,4] }
其他場(chǎng)合
由于數(shù)組的遍歷會(huì)調(diào)用遍歷器接口,所以任何接受數(shù)組作為參數(shù)的場(chǎng)合,其實(shí)都調(diào)用了遍歷器接口。比如for-of、Promise.all()、Promise.race()
生成器Generators生成器函數(shù)與普通函數(shù)不同的點(diǎn):普通函數(shù)使用function關(guān)鍵字聲明,生成器函數(shù)使用function*聲明,在生成器函數(shù)內(nèi)部,有類似return語(yǔ)法的yeild關(guān)鍵字,與return不同的是,生成器函數(shù)可以yeild多次,在函數(shù)執(zhí)行過程中,遇到y(tǒng)ield表達(dá)式立即暫停,后續(xù)可恢復(fù)執(zhí)行狀態(tài)。
function* question(name){ yield "你好" + name + "!" yield "希望你能喜歡" yield "下次再見" return "拜拜" } var iter = question("小明") iter.next() // {value: "你好小明!", done: false} iter.next() // {value: "希望你能喜歡", done: false} iter.next() // {value: "下次再見", done: false} iter.next() // {value: "拜拜", done: true}
generator函數(shù)在調(diào)用后,并不會(huì)立即執(zhí)行,而是返回一個(gè)iterator對(duì)象,每次生成器執(zhí)行到y(tǒng)ield語(yǔ)句后,生成器函數(shù)的堆棧結(jié)構(gòu)(本地變量、參數(shù)、臨時(shí)值、生成器內(nèi)部當(dāng)前的執(zhí)行位置)被移除堆棧。然而,生成器對(duì)象保留了對(duì)這個(gè)堆棧結(jié)構(gòu)的引用,所以稍后調(diào)用.next()方法可以重新激活堆棧結(jié)構(gòu)并且繼續(xù)執(zhí)行。不過生成器不是線程,它仍然處于JS單線程里。
如果運(yùn)行到后面沒有yield表達(dá)式,就會(huì)一直運(yùn)行到函數(shù)結(jié)束,直到return語(yǔ)句為止,并將return表達(dá)式的值賦值給最后返回對(duì)象的value值,如果沒有return語(yǔ)句,則返回對(duì)象的value值為undefined。
generator生成器是iterator的生成函數(shù),執(zhí)行g(shù)enerator函數(shù),返回的就是iterator迭代器。
function* gen(){ for(let i = 0; true; i++){ let reset = yield i if(reset){ i = -1 } } } let g = gen() g.next() // {value:0,done:false} g.next(true) // {value:0;done:false}
yield表達(dá)式本身沒有返回值,或者說總是返回undefined,next方法可以帶一個(gè)參數(shù),該參數(shù)就會(huì)被作為上一個(gè)yeild表達(dá)式的值。generator從暫停狀態(tài)到恢復(fù)運(yùn)行,它的上下文狀態(tài)是不變的,通過next方法傳入?yún)?shù),可以在generator函數(shù)開始運(yùn)行之后,繼續(xù)向函數(shù)內(nèi)部注入值。
throw方法function* gen(){ try { yield "123" }catch(e){ console.log("內(nèi)部捕獲",e) } } let g = gen() g.next() try { g.throw("a") g.throw("b") }catch(e){ console.log("外部捕獲","b") } // 內(nèi)部捕獲 a // 外部捕獲 b
上述代碼中,遍歷器對(duì)象g連續(xù)拋出錯(cuò)誤,第一個(gè)錯(cuò)誤被generator函數(shù)體內(nèi)的catch語(yǔ)句捕獲,第二次拋出錯(cuò)誤時(shí),由于catch語(yǔ)句已經(jīng)執(zhí)行過了,不會(huì)捕獲該錯(cuò)誤,所以這個(gè)錯(cuò)誤由函數(shù)體外的catch捕獲。如果函數(shù)內(nèi)部沒有try-catch語(yǔ)句,那么throw方法拋出的錯(cuò)誤將被外部的try-catch捕獲。遍歷器對(duì)象g調(diào)用throw方法后,拋出的異常被generator函數(shù)體捕獲以后,會(huì)附帶執(zhí)行下一條yield語(yǔ)句。一旦generator執(zhí)行過程拋出錯(cuò)誤,且沒有被內(nèi)部捕獲,generator函數(shù)就不會(huì)執(zhí)行下去了。如果此后再調(diào)用next方法,將返回對(duì)象{value:undefined,done:true}。
return方法function* gen(){ yield 1; yield 2; yiled 3; } var g = gen() g.next() // {value:1,done:false} g.return("end") // {value:"end",done:true} g.next() // {value:undefined,done:true}
如果generator函數(shù)內(nèi)部有try-finally代碼塊,那么return方法會(huì)推遲到finally代碼塊執(zhí)行完畢再執(zhí)行。
function* numbers () { yield 1; try { yield 2; yield 3; } finally { yield 4; yield 5; } yield 6; } var g = numbers(); g.next() // { value: 1, done: false } g.next() // { value: 2, done: false } g.return(7) // { value: 4, done: false } g.next() // { value: 5, done: false } g.next() // { value: 7, done: true }
next()、throw()、return()這三個(gè)方法都是讓generator函數(shù)恢復(fù)執(zhí)行,并且使用不同的語(yǔ)句替換yield表達(dá)式,next()是將yeild表達(dá)式替換成一個(gè)值,throw()是將yeild替換成一個(gè)throw語(yǔ)句,return()是將yield語(yǔ)句替換成一個(gè)return語(yǔ)句。
yield*在generator函數(shù)內(nèi)部再調(diào)用另一個(gè)generator函數(shù),默認(rèn)情況下是沒有效果的,這個(gè)時(shí)候就需要用到y(tǒng)ield*表達(dá)式,用來在一個(gè)generator函數(shù)內(nèi)執(zhí)行另一個(gè)generator函數(shù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/93306.html
摘要:聲明三大關(guān)鍵字聲明變量語(yǔ)法語(yǔ)法聲明常量語(yǔ)法聲明變量特性支持函數(shù)作用域支持預(yù)解析所謂變量提升支持重復(fù)聲明同域同名變量函數(shù)作用域局部作用域預(yù)解析重復(fù)聲明聲明變量推薦特性支持塊作用域不支持預(yù)解析不支持重復(fù)聲明同域同名變量塊作用域局部作用域不支持預(yù) 聲明 三大關(guān)鍵字 聲明變量: var (ES5語(yǔ)法) let (ES6語(yǔ)法) 聲明常量: const (ES6語(yǔ)法) var 聲明變量...
摘要:前言在理想的狀態(tài)下,你可以在深入了解之前了解和開發(fā)的所有知識(shí)。繼承另一個(gè)類的類,通常稱為類或類,而正在擴(kuò)展的類稱為類或類。這種類型的組件稱為無狀態(tài)功能組件。在你有足夠的信心構(gòu)建用戶界面之后,最好學(xué)習(xí)。 原文地址:JavaScript Basics Before You Learn React 原文作者: Nathan Sebhastian 寫在前面 為了不浪費(fèi)大家的寶貴時(shí)間,在開...
摘要:下載地址安裝一個(gè)好用的命令行工具在環(huán)境下,系統(tǒng)默認(rèn)的非常難用,所以我個(gè)人比較推薦大家使用或者。下載地址安裝在命令行工具中使用查看版本的方式確保與都安裝好之后,我們就可以安裝了。前端基礎(chǔ)進(jìn)階系列目錄 showImg(https://segmentfault.com/img/remote/1460000009654403?w=1240&h=272); 對(duì)于新人朋友來說,想要自己去搞定一個(gè)E...
摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:當(dāng)屬性是一個(gè)回調(diào)函數(shù)時(shí),函數(shù)接收底層元素或類實(shí)例取決于元素的類型作為參數(shù)。 手挽手帶你學(xué)React入門第一期,帶你熟悉React的語(yǔ)法規(guī)則,消除對(duì)JSX的恐懼感,由于現(xiàn)在開發(fā)中都是使用ES6語(yǔ)法開發(fā)React,所以這次也使用ES6的模式進(jìn)行教學(xué),如果大家對(duì)ES6不熟悉的話,先去看看class相關(guān)內(nèi)容吧,這里我也慢慢帶大家一步一步學(xué)會(huì)React。 視頻教程 視頻教程可移步我的個(gè)人博客:h...
閱讀 2504·2021-11-15 11:38
閱讀 1948·2021-11-05 09:37
閱讀 2257·2021-10-08 10:12
閱讀 2807·2019-08-30 15:55
閱讀 2112·2019-08-30 15:52
閱讀 1221·2019-08-29 13:24
閱讀 463·2019-08-26 18:27
閱讀 1473·2019-08-26 18:27