版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
ES6語法詳解(二)一、PromisePromise是一個對象,代表了未來某個將要發(fā)生的事件(,這個事件通常是一個異步操作)有了Promise對象,可以將異步操作以同步的流程表達出來,避免了層層嵌套的回調(diào)函數(shù)(俗稱'回調(diào)地獄')。ES6的Promise是一個構(gòu)造函數(shù),用來生成promise實例。1、promise對象3個狀態(tài)pending:初始化狀態(tài)fullfilled:成功狀態(tài)rejected:失敗狀態(tài)只有異步操作的結(jié)果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。一旦狀態(tài)改變,就不會再變,任何時候都可以得到這個結(jié)果。Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會再變了,會一直保持這個結(jié)果,這時就稱為resolved(已定型)。2、使用方法1、創(chuàng)建一個promise實例對象,參數(shù)是一個匿名函數(shù),這個匿名函數(shù)有兩個參數(shù),resolve和reject,2、每一個參數(shù)都是一個回調(diào)函數(shù)。然后,函數(shù)體中一般執(zhí)行的是異步操作,比如發(fā)起Ajax請求,或者開啟定時器等。3、異步操作成功時,調(diào)用resolve回調(diào)函數(shù),異步操作失敗時,調(diào)用reject回調(diào)函數(shù)。4、在初始化Promise實例對象的時候,Promise的狀態(tài)為pending;在調(diào)用resolve回調(diào)函數(shù)的時候,Promise的狀態(tài)為fullfilled,表示成功狀態(tài);在調(diào)用reject回調(diào)函數(shù)的時候,Promise的狀態(tài)為rejected,表示失敗狀態(tài);5、Promise的實例對象有一個方法then,參數(shù)為兩個匿名函數(shù),第一個匿名函數(shù)處理Promise的狀態(tài)為fullfilled的情況;第二個匿名函數(shù)處理Promise的狀態(tài)為rejected的情況;6、上面說到,在異步操作成功或者失敗的時候,會調(diào)用resolve和reject函數(shù),在這兩個回調(diào)函數(shù)中可以傳入?yún)?shù),這個參數(shù)可以直接帶入到then中兩個匿名函數(shù)的參數(shù)中使用。比如獲取到ajax的數(shù)據(jù),可以將獲取的數(shù)作為參數(shù)傳入resolve的參數(shù)中,然后會自動將這個參數(shù)傳入then的第一個匿名函數(shù)中,reject也一樣。用代碼表示:functiontimeout(ms){returnnewPromise((resolve,reject)=>{setTimeout(resolve,ms,'done');});}timeout(100).then((value)=>{console.log(value);});用圖示的方法表示:示例:letpromise=newPromise((resolve,reject)=>{console.log(111);//執(zhí)行異步操作setTimeout(()=>{console.log(222);//執(zhí)行異步操作成功,此時修改promise的狀態(tài)fullfilledresolve("success!");//執(zhí)行異步操作成功,此時修改promise的狀態(tài)rejectedreject("failed!");},2000);});promise.then((data)=>{//promise的狀態(tài)fullfilled的操作console.log("成功",data);},()=>{//promise的狀態(tài)rejected的操作console.log("失敗",data);});注意:當執(zhí)行到resolve("success!");修改promise的狀態(tài)fullfilled的時候,后面的reject("failed!");不會執(zhí)行。也就不會打印console.log("失敗");的語句。3、promise執(zhí)行順序Promise新建后就會立即執(zhí)行。letpromise=newPromise(function(resolve,reject){console.log('Promise');resolve();});promise.then(function(){console.log('resolved.');});console.log('Hi!');//Promise//Hi!//resolved上面代碼中,Promise新建后立即執(zhí)行,所以首先輸出的是Promise。然后,then方法指定的回調(diào)函數(shù),將在當前腳本所有同步任務(wù)執(zhí)行完才會執(zhí)行,所以resolved最后輸出。newPromise((resolve,reject)=>{resolve(1);console.log(2);}).then(r=>{console.log(r);});//2//1上面代碼中,調(diào)用resolve(1)以后,后面的console.log(2)還是會執(zhí)行,并且會首先打印出來。這是因為立即resolved的Promise是在本輪事件循環(huán)的末尾執(zhí)行,總是晚于本輪循環(huán)的同步任務(wù)。然而——一般來說,調(diào)用resolve或reject以后,Promise的使命就完成了,后繼操作應(yīng)該放到then方法里面,而不應(yīng)該直接寫在resolve或reject的后面。所以,最好在它們前面加上return語句,這樣就不會有意外。newPromise((resolve,reject)=>{returnresolve(1);//后面的語句不會執(zhí)行console.log(2);})4、小例子使用promise獲取新聞內(nèi)容和評論內(nèi)容://定義一個請求news的方法functiongetNews(url){//創(chuàng)建一個promise對象letpromise=newPromise((resolve,reject)=>{//初始化promise狀態(tài)為pending//啟動異步任務(wù),發(fā)起Ajax請求//1.創(chuàng)建一個XMLHttpRequest類型的對象letrequest=newXMLHttpRequest();//4.指定xhr狀態(tài)變化事件處理函數(shù)request.onreadystatechange=function(){if(request.readyState===4){if(request.status===200){letnews=request.response;resolve(news);}else{reject('請求失敗了...');}}};request.responseType='json';//設(shè)置返回的數(shù)據(jù)類型//2.打開與一個網(wǎng)址之間的連接request.open("GET",url);//規(guī)定請求的方法,創(chuàng)建鏈接//3.通過鏈接發(fā)送一次請求request.send();//發(fā)送})//只有將promise返回,才可以調(diào)用then方法returnpromise;};//調(diào)用getNews,獲取新聞內(nèi)容,其中一個字節(jié)為評論內(nèi)容的地址getNews('http://localhost:3000/news?id=2').then((news)=>{//獲取到新聞內(nèi)容console.log(news);//document.write(JSON.stringify(news));//獲取新聞內(nèi)容中的評論地址console.log('http://localhost:3000'+mentsUrl);//遞歸獲取新聞評論內(nèi)容,并且返回promise對象,以便鏈式then方法。returngetNews('http://localhost:3000'+mentsUrl);},(error)=>{alert(error);}).then((comments)=>{//then方法可以鏈式編程console.log(comments);//把新聞的評論部分已json的格式打印出來顯示document.write('<br><br><br><br><br>'+JSON.stringify(comments));},(error)=>{alert(error);});5、catchPtotype.catch方法是.then(null,rejection)或.then(undefined,rejection)的別名,用于指定發(fā)生錯誤時的回調(diào)函數(shù)。當狀態(tài)就會變?yōu)閞ejected,就會調(diào)用catch方法指定的回調(diào)函數(shù),處理這個錯誤。另外,then方法指定的回調(diào)函數(shù),如果運行中拋出錯誤,也會被catch方法捕獲。newPromise((resolve,reject)=>{reject(1);console.log(2);}).catch(r=>{console.log(r);});//2//1一般來說,不要在then方法里面定義Reject狀態(tài)的回調(diào)函數(shù)(即then的第二個參數(shù)),總是使用catch方法。//不好的寫法promise.then(function(data){//success},function(err){//error});//好的寫法promise.then(function(data){//cb//success}).catch(function(err){//error});上面代碼中,第二種寫法要好于第一種寫法,理由是第二種寫法可以捕獲前面then方法執(zhí)行中的錯誤,也更接近同步的寫法(try/catch)。因此,建議總是使用catch方法,而不使用then方法的第二個參數(shù)。6、finallyfinally方法用于指定不管Promise對象最后狀態(tài)如何,都會執(zhí)行的操作。該方法是ES2018引入標準的。promise.then(result=>{···}).catch(error=>{···}).finally(()=>{···});上面代碼中,不管promise最后的狀態(tài),在執(zhí)行完then或catch指定的回調(diào)函數(shù)以后,都會執(zhí)行finally方法指定的回調(diào)函數(shù)。7、Promise靜態(tài)方法7.1、all和race有時候需要同時處理多個ajax請求,如何在都獲取到數(shù)據(jù)的時候才進行下一步操作呢?Promise.all
就派上用場了。Promise.all([ajax1(),ajax2(),ajax3()]) .then(function(res){//res處理}).catch(function(err){//err錯誤處理})其中ajax1,ajax2,ajax3
返回值都是Promise實例。當ajax1(),ajax2(),ajax3()狀態(tài)全為
fulfilled
的時候,才會調(diào)用then方法。當ajax1(),ajax2(),ajax3()狀態(tài)有一個為
rejected
的時候,就會調(diào)用catch方法。而rece與all用法相同,但是結(jié)果相反:Promise.rece([ajax1(),ajax2(),ajax3()]) .then(function(res){//res處理}).catch(function(err){//err錯誤處理})當ajax1(),ajax2(),ajax3()狀態(tài)有一個為
fulfilled
的時候,就會調(diào)用then方法。當ajax1(),ajax2(),ajax3()狀態(tài)全為
rejected
的時候,才會調(diào)用catch方法。7.2、resolve和rejectPromise.resolve(value)方法返回一個已給定值解析后的新的Promise對象,從而能繼續(xù)使用then的鏈式方法調(diào)用。varpromise1=Promise.resolve(123);promise.then(function(value){console.log(value);//expectedoutput:123});而
Promise.reject()
和resolve一樣。二、SymbolES5的對象屬性名都是字符串,這容易造成屬性名的沖突。比如,你使用了一個他人提供的對象,但又想為這個對象添加新的方法(mixin模式),新方法的名字就有可能與現(xiàn)有方法產(chǎn)生沖突。如果有一種機制,保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的沖突。這就是ES6引入Symbol的原因。1、Symbol屬性對應(yīng)的值是唯一的,解決命名沖突問題Symbol是一種新的數(shù)據(jù)類型,跟String,Number,Object,Boolean,null,undefined并列。Symbol值通過Symbol函數(shù)生成。這就是說,對象的屬性名現(xiàn)在可以有兩種類型,一種是原來就有的字符串,另一種就是新增的Symbol類型。凡是屬性名屬于Symbol類型,就都是獨一無二的,可以保證不會與其他屬性名產(chǎn)生沖突。lets=Symbol();typeofs;//symbol上面代碼中,變量s就是一個獨一無二的值。typeof運算符的結(jié)果,表明變量s是Symbol數(shù)據(jù)類型,而不是字符串之類的其他類型。注意,Symbol函數(shù)前不能使用new命令,否則會報錯。這是因為生成的Symbol是一個原始類型的值,不是對象。也就是說,由于Symbol值不是對象,所以不能添加屬性?;旧?,它是一種類似于字符串的數(shù)據(jù)類型。Symbol函數(shù)可以接受一個字符串作為參數(shù),表示對Symbol實例的描述,主要是為了在控制臺顯示,或者轉(zhuǎn)為字符串時,比較容易區(qū)分。lets1=Symbol('foo');lets2=Symbol('bar');s1//Symbol(foo)s2//Symbol(bar)s1.toString()//"Symbol(foo)"s2.toString()//"Symbol(bar)"上面代碼中,s1和s2是兩個Symbol值。如果不加參數(shù),它們在控制臺的輸出都是Symbol(),不利于區(qū)分。有了參數(shù)以后,就等于為它們加上了描述,輸出的時候就能夠分清,到底是哪一個值。2、Symbol值不能與其他數(shù)據(jù)進行計算,包括同字符串拼串letsym=Symbol('Mysymbol');"yoursymbolis"+sym//TypeError:can'tconvertsymboltostring`yoursymbolis${sym}`//TypeError:can'tconvertsymboltostring3、作為屬性名的Symbol由于每一個Symbol值都是不相等的,這意味著Symbol值可以作為標識符,用于對象的屬性名,就能保證不會出現(xiàn)同名的屬性。這對于一個對象由多個模塊構(gòu)成的情況非常有用,能防止某一個鍵被不小心改寫或覆蓋。letmySymbol=Symbol();//第一種寫法leta={};a[mySymbol]='Hello!';//第二種寫法leta={[mySymbol]:'Hello!'};//第三種寫法leta={};Object.defineProperty(a,mySymbol,{value:'Hello!'});//以上寫法都得到同樣結(jié)果a[mySymbol]//"Hello!"注意,Symbol值作為對象屬性名時,不能用點運算符。a.mySymbol='Hello!';4、forin,forof遍歷時不會遍歷symbol屬性letobj={username:'Daotin',age:18};obj[symbol]='hello';obj[symbol]='symbol';console.log(obj);for(letiinobj){console.log(i);}5、內(nèi)置的Symbol值除了定義自己使用的Symbol值以外,ES6還提供了11個內(nèi)置的Symbol值,指向語言內(nèi)部使用的方法。6、Symbol.hasInstance對象的Symbol.hasInstance屬性,指向一個內(nèi)部方法。當其他對象使用instanceof運算符,判斷是否為該對象的實例時,會調(diào)用這個方法。比如,fooinstanceofFoo在語言內(nèi)部,實際調(diào)用的是Foo[Symbol.hasInstance](foo)。7、Symbol.iterator對象的Symbol.iterator屬性,指向該對象的默認遍歷器方法。三、IteratorIterator是迭代器(遍歷器)的意思。JavaScript原有的表示“集合”的數(shù)據(jù)結(jié)構(gòu),主要是數(shù)組(Array)和對象(Object),ES6又添加了Map和Set。這樣就有了四種數(shù)據(jù)集合,用戶還可以組合使用它們,定義自己的數(shù)據(jù)結(jié)構(gòu),比如數(shù)組的成員是Map,Map的成員是對象。這樣就需要一種統(tǒng)一的接口機制,來處理所有不同的數(shù)據(jù)結(jié)構(gòu)。遍歷器(Iterator)就是這樣一種機制。它是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機制。任何數(shù)據(jù)結(jié)構(gòu)只要部署Iterator接口,就可以完成遍歷操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)。Iterator的作用:為各種數(shù)據(jù)結(jié)構(gòu),提供一個統(tǒng)一的、簡便的訪問接口使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列ES6創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator接口主要供for...of消費。Iterator的遍歷過程:(1)創(chuàng)建一個指針對象,指向當前數(shù)據(jù)結(jié)構(gòu)的起始位置。也就是說,遍歷器對象本質(zhì)上,就是一個指針對象。(2)第一次調(diào)用指針對象的next方法,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個成員。(3)第二次調(diào)用指針對象的next方法,指針就指向數(shù)據(jù)結(jié)構(gòu)的第二個成員。(4)不斷調(diào)用指針對象的next方法,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置。每一次調(diào)用next方法,都會返回數(shù)據(jù)結(jié)構(gòu)的當前成員的信息。具體來說,就是返回一個包含value和done兩個屬性的對象。其中,value屬性是當前成員的值,done屬性是一個布爾值,表示遍歷是否結(jié)束。下面是一個模擬next方法返回值的例子。varit=makeIterator(['a','b']);it.next()//{value:"a",done:false}it.next()//{value:"b",done:false}it.next()//{value:undefined,done:true}functionmakeIterator(array){varnextIndex=0;return{next:function(){returnnextIndex<array.length?{value:array[nextIndex++],done:false}:{value:undefined,done:true};}};}對于遍歷器對象來說,done:false和value:undefined屬性都是可以省略的,因此上面的makeIterator函數(shù)可以簡寫成下面的形式。functionmakeIterator(array){varnextIndex=0;return{next:function(){returnnextIndex<array.length?{value:array[nextIndex++]}:{done:true};}};}1、默認Iterator接口ES6規(guī)定,默認的Iterator接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性,或者說,一個數(shù)據(jù)結(jié)構(gòu)只要具有Symbol.iterator屬性,就可以認為是“可遍歷的”(iterable)。Symbol.iterator屬性本身是一個函數(shù),就是當前數(shù)據(jù)結(jié)構(gòu)默認的遍歷器生成函數(shù)。執(zhí)行這個函數(shù),就會返回一個遍歷器。至于屬性名Symbol.iterator,它是一個表達式,返回Symbol對象的iterator屬性,這是一個預(yù)定義好的、類型為Symbol的特殊值,所以要放在方括號內(nèi).constobj={[Symbol.iterator]:function(){return{next:function(){return{value:1,done:true};}};}};上面代碼中,對象obj是可遍歷的(iterable),因為具有Symbol.iterator屬性。執(zhí)行這個屬性,會返回一個遍歷器對象。該對象的根本特征就是具有next方法。每次調(diào)用next方法,都會返回一個代表當前成員的信息對象,具有value和done兩個屬性。ES6的有些數(shù)據(jù)結(jié)構(gòu)原生具備Iterator接口(比如數(shù)組),即不用任何處理,就可以被for...of循環(huán)遍歷。原因在于,這些數(shù)據(jù)結(jié)構(gòu)原生部署了Symbol.iterator屬性(詳見下文),另外一些數(shù)據(jù)結(jié)構(gòu)沒有(比如對象)。凡是部署了Symbol.iterator屬性的數(shù)據(jù)結(jié)構(gòu),就稱為部署了遍歷器接口。調(diào)用這個接口,就會返回一個遍歷器對象。原生具備Iterator接口的數(shù)據(jù)結(jié)構(gòu)如下。ArrayMapSetStringTypedArray函數(shù)的arguments對象NodeList對象下面的例子是數(shù)組的Symbol.iterator屬性。letarr=['a','b','c'];letiter=arr[Symbol.iterator]();iter.next()//{value:'a',done:false}iter.next()//{value:'b',done:false}iter.next()//{value:'c',done:false}iter.next()//{value:undefined,done:true}上面代碼中,變量arr是一個數(shù)組,原生就具有遍歷器接口,部署在arr的Symbol.iterator屬性上面。所以,調(diào)用這個屬性,就得到遍歷器對象。對于原生部署Iterator接口的數(shù)據(jù)結(jié)構(gòu),不用自己寫遍歷器生成函數(shù),for...of循環(huán)會自動遍歷它們。除此之外,其他數(shù)據(jù)結(jié)構(gòu)(主要是對象)的Iterator接口,都需要自己在Symbol.iterator屬性上面部署,這樣才會被for...of循環(huán)遍歷。一個對象如果要具備可被for...of循環(huán)調(diào)用的Iterator接口,就必須在Symbol.iterator的屬性上部署遍歷器生成方法(原型鏈上的對象具有該方法也可)。2、調(diào)用Iterator接口的場合使用解構(gòu)賦值以及...三點運算符時會調(diào)用iterator接口letarr1=[1,2,3,4,5];let[value1,...arr2]=arr1;for..of..遍歷//原生測試數(shù)組letarr3=[1,2,'kobe',true];for(letiofarr3){console.log(i);}//字符串stringletstr='abcdefg';for(letitemofstr){console.log(item);}四、GeneratorGenerator函數(shù)是ES6提供的一種異步編程解決方案。Generator函數(shù)有多種理解角度。語法上,首先可以把它理解成,Generator函數(shù)是一個狀態(tài)機,封裝了多個內(nèi)部狀態(tài)。執(zhí)行Generator函數(shù)會返回一個遍歷器對象,也就是說,Generator函數(shù)除了狀態(tài)機,還是一個遍歷器對象生成函數(shù)。返回的遍歷器對象,可以依次遍歷Generator函數(shù)內(nèi)部的每一個狀態(tài)。形式上,Generator函數(shù)是一個普通函數(shù),但是有兩個特征。一是,function關(guān)鍵字與函數(shù)名之間有一個星號;二是,函數(shù)體內(nèi)部使用yield表達式,定義不同的內(nèi)部狀態(tài)(yield在英語里的意思就是“產(chǎn)出”)。function*myGenerator(){yield'hello';yield'world';return'ending';}//返回值是一個遍歷器對象varhw=myGenerator();上面代碼定義了一個Generator函數(shù)helloWorldGenerator,它內(nèi)部有兩個yield表達式(hello和world),即該函數(shù)有三個狀態(tài):hello,world和return語句(結(jié)束執(zhí)行)。然后,Generator函數(shù)的調(diào)用方法與普通函數(shù)一樣,也是在函數(shù)名后面加上一對圓括號。不同的是,調(diào)用Generator函數(shù)后,該函數(shù)并不執(zhí)行,返回的也不是函數(shù)運行結(jié)果,而是一個指向內(nèi)部狀態(tài)的指針對象,也就是上一章介紹的遍歷器對象(IteratorObject)。下一步,必須調(diào)用遍歷器對象的next方法,使得指針移向下一個狀態(tài)。也就是說,每次調(diào)用next方法,內(nèi)部指針就從函數(shù)頭部或上一次停下來的地方開始執(zhí)行,直到遇到下一個yield表達式(或return語句)為止。換言之,Generator函數(shù)是分段執(zhí)行的,yield表達式是暫停執(zhí)行的標記,而next方法可以恢復(fù)執(zhí)行。hw.next()//{value:'hello',done:false}hw.next()//{value:'world',done:false}hw.next()//{value:'ending',done:true}hw.next()//{value:undefined,done:true}總結(jié)一下,調(diào)用Generator函數(shù),返回一個遍歷器對象,代表Generator函數(shù)的內(nèi)部指針。以后,每次調(diào)用遍歷器對象的next方法,就會返回一個有著value和done兩個屬性的對象。value屬性表示當前的內(nèi)部狀態(tài)的值,是yield表達式后面那個表達式的值;done屬性是一個布爾值,表示是否遍歷結(jié)束。1、yield表達式由于Generator函數(shù)返回的遍歷器對象,只有調(diào)用next方法才會遍歷下一個內(nèi)部狀態(tài),所以其實提供了一種可以暫停執(zhí)行的函數(shù)。yield表達式就是暫停標志。遍歷器對象的next方法的運行邏輯如下:(1)遇到y(tǒng)ield表達式,就暫停執(zhí)行后面的操作,并將緊跟在yield后面的那個表達式的值,作為返回的對象的value屬性值。(2)下一次調(diào)用next方法時,再繼續(xù)往下執(zhí)行,直到遇到下一個yield表達式。(3)如果沒有再遇到新的yield表達式,就一直運行到函數(shù)結(jié)束,直到return語句為止,并將return語句后面的表達式的值,作為返回的對象的value屬性值。(4)如果該函數(shù)沒有return語句,則返回的對象的value屬性值為undefined。需要注意的是,yield表達式后面的表達式,只有當調(diào)用next方法、內(nèi)部指針指向該語句時才會執(zhí)行,因此等于為JavaScript提供了手動的“惰性求值”(LazyEvaluation)的語法功能。yield表達式與return語句區(qū)別:相似之處在于,都能返回緊跟在語句后面的那個表達式的值。區(qū)別在于每次遇到y(tǒng)ield,函數(shù)暫停執(zhí)行,下一次再從該位置繼續(xù)向后執(zhí)行,而return語句不具備位置記憶的功能。一個函數(shù)里面,只能執(zhí)行一次(或者說一個)return語句,但是可以執(zhí)行多次(或者說多個)yield表達式。正常函數(shù)只能返回一個值,因為只能執(zhí)行一次return;Generator函數(shù)可以返回一系列的值,因為可以有任意多個yield。2、與Iterator接口的關(guān)系任意一個對象的Symbol.iterator方法,等于該對象的遍歷器生成函數(shù),調(diào)用該函數(shù)會返回該對象的一個遍歷器對象。由于Generator函數(shù)就是遍歷器生成函數(shù),因此可以把Generator賦值給對象的Symbol.iterator屬性,從而使得該對象具有Iterator接口。varmyIterable={};myIterable[Symbol.iterator]=function*(){yield1;yield2;yield3;};[...myIterable]//[1,2,3]上面代碼中,Generator函數(shù)賦值給Symbol.iterator屬性,從而使得myIterable對象具有了Iterator接口,可以被...運算符遍歷了。3、next方法的參數(shù)yield表達式本身沒有返回值,或者說總是返回undefined。next方法可以帶一個參數(shù),該參數(shù)就會被當作上一個yield表達式的返回值。function*f(){for(vari=0;true;i++){varreset=yieldi;if(reset){i=-1;}}}varg=f();g.next()//{value:0,done:false}g.next()//{value:1,done:false}g.next(true)//{value:0,done:false}上面代碼先定義了一個可以無限運行的Generator函數(shù)f,如果next方法沒有參數(shù),每次運行到y(tǒng)ield表達式,變量reset的值總是undefined。當next方法帶一個參數(shù)true時,變量reset就被重置為這個參數(shù)(即true),因此i會等于-1,下一輪循環(huán)就會從-1開始遞增。4、for...of循環(huán)for...of循環(huán)可以自動遍歷Generator函數(shù)時生成的Iterator對象,且此時不再需要調(diào)用next方法。function*foo(){yield1;yield2;yield3;yield4;yield5;return6;}for(letvoffoo()){console.log(v);}//12345上面代碼使用for...of循環(huán),依次顯示5個yield表達式的值。這里需要注意,一旦next方法的返回對象的done屬性為true,for...of循環(huán)就會中止,且不包含該返回對象,所以上面代碼的return語句返回的6,不包括在for...of循環(huán)之中。下面是一個利用Generator函數(shù)和for...of循環(huán),實現(xiàn)斐波那契數(shù)列的例子。function*foo(){let[prev,current]=[0,1];for(;;){yieldcurrent;[prev,current]=[current,prev+current];}}for(letnoffoo()){if(n>1000)break;console.log(n);}Generator小案例需求:1、發(fā)送Ajax請求獲取新聞內(nèi)容2、新聞內(nèi)容獲取成功再次發(fā)送請求獲取對應(yīng)的新聞評論內(nèi)容3、新聞內(nèi)容獲取失敗則不需要再次發(fā)送請求。functiongetNews(url){$.get(url,function(data){console.log(data);leturls="http://localhost:3000"+mentUrl;//urls可以作為第一個yield的返回值//執(zhí)行第二條yeild語句,發(fā)送請求新聞評論//獲取的評論地址如何傳入到y(tǒng)ieldgetNews(urls);靠的是第二次//發(fā)送next時傳入的參數(shù),就是評論地址sx.next(urls);});}function*sendXml(){//發(fā)送請求新聞內(nèi)容leturls=yieldgetNews("http://localhost:3000/news?id=2");//請求新聞評論內(nèi)容yieldgetNews(urls);}letsx=sendXml();//執(zhí)行第一條yeild語句,發(fā)送請求新聞sx.next();五、asyncES2017標準引入了async函數(shù),使得異步操作變得更加方便。async函數(shù)是什么?一句話,它就是Generator函數(shù)的語法糖。語法:asyncfunctionfoo(){await異步操作;await異步操作;}特點:1、不需要像Generator去調(diào)用next方法,遇到await等待,當前的異步操作完成就往下執(zhí)行2、返回的總是Promise對象,可以用then方法進行下一步操作3、async取代Generator函數(shù)的星號*,await取代Generator的yield4、語意上更為明確,使用簡單,經(jīng)臨床驗證,暫時沒有任何副作用舉個栗子:asyncfunctiontimeout(ms){returnnewPromise(resolve=>{setTimeout(resolve,ms);})}asyncfunctionasyncPrint(value,ms){console.log('函數(shù)執(zhí)行',newDate().toTimeString());awaittimeout(ms);console.log('延時時間',newDate().toTimeString());console.log(value);}console.log(asyncPrint('helloasync',2000));asyncPrint執(zhí)行的時候,先打印的是“函數(shù)執(zhí)行”,之后進入到timeout函數(shù),由于是異步執(zhí)行,但是timeout未執(zhí)行完成,所以await在等待,相當于掛起。而這一邊asyncPrint會立即返回一個Promise對象。之后另一邊timeout、執(zhí)行完成,打印出“延時時間”,之后打印“helloasync”。async函數(shù)內(nèi)部return語句返回的值,會成為then方法回調(diào)函數(shù)的參數(shù)。下面代碼中,函數(shù)f內(nèi)部return命令返回的值,會被then方法回調(diào)函數(shù)接收到。asyncfunctionf(){return'helloworld';}f().then(v=>console.log(v))//"helloworld"1、await命令正常情況下,await命令后面是一個Promise對象。如果不是,會被轉(zhuǎn)成一個立即resolve的Promise對象。而
resolve參數(shù)就是await的返回值。asyncfunctionf(){returnawait123;}f().then(v=>console.log(v))//123await命令后面的Promise對象如果變?yōu)閞eject狀態(tài),則reject的參數(shù)會被catch方法的回調(diào)函數(shù)接收到。asyncfunctionf(){awaitPromise.reject('出錯了');}f().then(v=>console.log(v)).catch(e=>console.log(e))//出錯了2、案例:獲取新聞和評論內(nèi)容asyncfunctionsendXml(url){returnnewPromise((resolve,reject)=>{$.ajax({url,type:'GET',success:data=>resolve(data),error:error=>reject(error)})})}asyncfunctiongetNews(url){letresult=awaitsendXml(url);letresult2=awaitsendXml(url);console.log(result,result2);}getNews('http://localhost:3000/news?id=2')六、ClassJavaScript語言中,生成實例對象的傳統(tǒng)方法是通過構(gòu)造函數(shù)。下面是一個例子。functionPoint(x,y){this.x=x;this.y=y;}Ptotype.toString=function(){return'('+this.x+','+this.y+')';};varp=newPoint(1,2);上面這種寫法跟傳統(tǒng)的面向?qū)ο笳Z言(比如C++和Java)差異很大,ES6提供了更接近傳統(tǒng)語言的寫法,引入了Class(類)這個概念,作為對象的模板。通過class關(guān)鍵字,可以定義類。//定義類classPoint{constructor(x,y){this.x=x;this.y=y;}toString(){return'('+this.x+','+this.y+')';}}1、constructor方法constructor方法是類的默認方法,通過new命令生成對象實例時,自動調(diào)用該方法。一個類必須有constructor方法,如果沒有顯式定義,一個空的constructor方法會被默認添加。Class的繼承Class可以通過extends關(guān)鍵字實現(xiàn)繼承,這比ES5的通過修改原型鏈實現(xiàn)繼承,要清晰和方便很多。classPoint{}//ColorPoint繼承PointclassColorPointextendsPoint{}上面代碼定義了一個ColorPoint類,該類通過extends關(guān)鍵字,繼承了Point類的所有屬性和方法。classColorPointextendsPoint{constructor(x,y,color){super(x,y);//調(diào)用父類的constructor(x,y)this.color=color;}toString(){returnthis.color+''+super.toString();//調(diào)用父類的toString()}}上面代碼中,constructor方法和toString方法之中,都出現(xiàn)了super關(guān)鍵字,它在這里表示父類的構(gòu)造函數(shù),用來新建父類的this對象。子類必須在constructor方法中調(diào)用super方法,否則新建實例時會報錯。這是因為子類自己的this對象,必須先通過父類的構(gòu)造函數(shù)完成塑造,得到與父類同樣的實例屬性和方法,然后再對其進行加工,加上子類自己的實例屬性和方法。如果不調(diào)用super方法,子類就得不到this對象。七、字符串的擴展includes(str)
:判斷是否包含指定的字符串startsWith(str):判斷是否以指定字符串開頭endsWith(str):判斷是否以指定字符串結(jié)尾repeat(count):重復(fù)指定次數(shù)letstr='abcdefg';console.log(str.includes('a'));//trueconsole.log(str.includes('h'));//false//startsWith(str):判斷是否以指定字符串開頭console.log(str.startsWith('ab'));//trueconsole.log(str.startsWith('ac'));//false//endsWith(str):判斷是否以指定字符串結(jié)尾console.log(str.endsWith('fg'));//trueconsole.log(str.endsWith('d'));//false//repeat(count):重復(fù)指定次數(shù)aconsole.log(str.repeat(3));//abcdefgabcdefgabcdefg二、數(shù)值的擴展二進制與八進制數(shù)值表示法:二進制用0b開頭,八進制用0o開頭。Number.isFinite(i):判斷是否是有限大的數(shù)Number.isNaN(i)
:判斷是否是NaNNumber.isInteger(i)
:判斷是否是整數(shù)Number.parseInt(str):將字符串轉(zhuǎn)換為對應(yīng)的數(shù)值Math.trunc(i):直接去除小數(shù)部分console.log(0b1010);//10console.log(0o56);//46console.log('--------------------');//Number.isFinite(i):判斷是否是有限大的數(shù)console.log(Number.isFinite(NaN));//falseconsole.log(Number.isFinite(5));//trueconsole.log(Number.isFinite(Infinity));//falseconsole.log('--------------------');//Number.isNaN(i):判斷是否是NaNconsole.log(Number.isNaN(NaN));//trueconsole.log(Number.isNaN(5));//falseconsole.log(Number.isNaN(undefined));//falseconsole.log('--------------------');//Number.isInteger(i):判斷是否是整數(shù)console.log(Number.isInteger(5.23));//falseconsole.log(Number.isInteger(5.0));//trueconsole.log(Number.isInteger(5));//trueconsole.log('--------------------');//Number.parseInt(str):將字符串轉(zhuǎn)換為對應(yīng)的數(shù)值console.log(Number.parseInt('123abc'));//123console.log(Number.parseInt('a123abc'));//NaNconsole.log('--------------------');//Math.trunc(i):直接去除小數(shù)部分console.log(Math.trunc(13.123));//13三、數(shù)組擴展Array.from(v):將偽數(shù)組對象或可遍歷對象轉(zhuǎn)換為真數(shù)組Array.of(v1,v2,v3)
:將一系列值轉(zhuǎn)換成數(shù)組find(function(value,index,arr){returntrue})
:找出第一個滿足條件返回true的元素findIndex(function(value,index,arr){returntrue}):找出第一個滿足條件返回true的元素下標<body><button>測試1</button><br><button>測試2</button><br><button>測試3</button><br><!--1.Array.from(v):將偽數(shù)組對象或可遍歷對象轉(zhuǎn)換為真數(shù)組2.Array.of(v1,v2,v3):將一系列值轉(zhuǎn)換成數(shù)組3.find(function(value,index,arr){returntrue}):找出第一個滿足條件返回true的元素4.findIndex(function(value,index,arr){returntrue}):找出第一個滿足條件返回true的元素下標--><scripttype="text/javascript">//Array.from(v):將偽數(shù)組對象或可遍歷對象轉(zhuǎn)換為真數(shù)組,返回值即為真數(shù)組//使用DOM操縱獲取的元素集合是偽數(shù)組。letbtns=document.getElementsByTagName('button');console.log(btns.length);//3Array.from(btns).forEach(function(item,index){console.log(item,index);});//Array.of(v1,v2,v3):將一系列單獨的值轉(zhuǎn)換成數(shù)組
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 物流運輸與配送服務(wù)管理制度
- 明確易燃易爆物品的使用及貯存管理制度
- 圓管涵施工流程中的技術(shù)難點與解決方案
- 企業(yè)民族團結(jié)文化建設(shè)計劃
- 航空維修施工流程及標準
- 提高中學(xué)教育質(zhì)量的有效措施
- LED顯示屏項目應(yīng)急預(yù)案及安全措施
- 壽險市場調(diào)研與分析工作計劃
- 建筑工程PMC進度控制計劃
- 八年級美術(shù)數(shù)字藝術(shù)教學(xué)計劃
- 2022年湖北省武漢市中考數(shù)學(xué)試卷含解析
- TLFSA 003-2020 危害分析與關(guān)鍵控制點(HACCP)體系調(diào)味面制品生產(chǎn)企業(yè)要求
- LY/T 2244.3-2014自然保護區(qū)保護成效評估技術(shù)導(dǎo)則第3部分:景觀保護
- 紀律教育月批評與自我批評五篇
- GB/T 26480-2011閥門的檢驗和試驗
- GB/T 13342-2007船用往復(fù)式液壓缸通用技術(shù)條件
- 藥店員工教育培訓(xùn)資料
- GB 20371-2016食品安全國家標準食品加工用植物蛋白
- 【英語手寫體】26英文字母手寫體描紅書寫字帖
- 實習(xí)護生壓瘡相關(guān)知識掌握情況及預(yù)防態(tài)度的調(diào)查問卷
- 《駱駝祥子》第(9、10、11、12)章檢測題
評論
0/150
提交評論