成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

ES6常用知識(shí)點(diǎn)概述

keithyau / 3314人閱讀

摘要:那之前的例子來(lái)使用一下的話,你會(huì)發(fā)現(xiàn)瀏覽器報(bào)錯(cuò)了,如圖定義的變量不允許二次修改。如圖箭頭函數(shù)沒(méi)有它自己的值,箭頭函數(shù)內(nèi)的值繼承自外圍作用域。如圖這里兩邊的結(jié)構(gòu)沒(méi)有一致,如果是的話,是可以正常解構(gòu)的。

前言

國(guó)慶假期已過(guò)一半,來(lái)篇干貨壓壓驚。

ES6,并不是一個(gè)新鮮的東西,ES7、ES8已經(jīng)趕腳了。但是,東西不在于新,而在于總結(jié)。每個(gè)學(xué)前端的人,身邊也必定有本阮老師的《ES6標(biāo)準(zhǔn)入門(mén)》或者翻譯的《深入理解ECMAScript6》。本篇主要是對(duì)ES6的一些常用知識(shí)點(diǎn)進(jìn)行一個(gè)總結(jié)。如果你喜歡我的文章,歡迎評(píng)論,歡迎Star~。歡迎關(guān)注我的github博客

正文

我們會(huì)更具之前的羅列的內(nèi)容進(jìn)行一個(gè)深入的分析。

變量的新定義——let和const

在ES6沒(méi)有被普及時(shí),我們會(huì)用的變量定義的方法是var。其實(shí),var對(duì)于一個(gè)剛剛接觸js的人說(shuō),或許并不覺(jué)得怪異。但是,對(duì)于一個(gè)開(kāi)發(fā)者而言,或許會(huì)在內(nèi)心抨擊它。因?yàn)樗褪莏avascript的敗筆之一,在其他語(yǔ)言看來(lái)的一個(gè)怪胎。那我們就來(lái)看看怪在何處呢?

可以重復(fù)定義。不知道你的代碼里面會(huì)不會(huì)出現(xiàn)這樣子的代碼,舉例:

var a = 10;
var a = 11;

或許,你會(huì)看到這樣子的寫(xiě)法覺(jué)得沒(méi)啥,那么你很厲(wei)害(xian)。其實(shí),這樣子的壞處不言而喻。在大型的工程化開(kāi)發(fā)中,你定義一個(gè)a,我定義一個(gè)a,還有千千萬(wàn)萬(wàn)個(gè)你和我,這時(shí),技術(shù)總監(jiān)就該著急了。所以,這是var的第一點(diǎn)令人討厭的地方,但是如果你會(huì)說(shuō)不是有嚴(yán)格模式嘛。的確,嚴(yán)格模式做了一定的規(guī)范,但是我們不加以討論。畢竟,這時(shí)ES6的地盤(pán)(^-^)。

可隨意修改。何為可隨意修改?并不是指變量,而是指常量。舉例:

var PI = 3.1415926
PI = 4.1415926

從例子中,我們可以看到,PI是一個(gè)我們經(jīng)常會(huì)使用的常量,是公認(rèn)的不可變動(dòng)的。但在javascript中并不是如此。那天,如果你的PI被你們公司新晉的實(shí)習(xí)生改了,可能你找錯(cuò)誤都得找半天,但這可不是實(shí)習(xí)生的鍋,也許,他并不知道這里是個(gè)常量。不過(guò),這種情況也是玩笑話(^_^)。

沒(méi)有塊級(jí)作用域。如果你連塊級(jí)作用域都不知道的話,趕緊收藏一下^_^,回頭再來(lái)看哈~,舉例:

if(true){
var i = 10;
}
console.log(i);  //10

相信,這變量不存在塊級(jí)作用域給我們帶來(lái)過(guò)不少麻煩吧。不知道啥時(shí)候,又得在循環(huán)中套一層閉包呢。而且,在非js開(kāi)發(fā)者來(lái)說(shuō),可能覺(jué)得是個(gè)特(xiao)點(diǎn)(hua)。

所以,let和const就來(lái)拯救var了,如何一個(gè)拯救法呢?

在同一個(gè)塊級(jí)作用域中,不允許重復(fù)定義。那之前的例子來(lái)使用一下的話,你會(huì)發(fā)現(xiàn)瀏覽器報(bào)錯(cuò)了,如圖:

![let](https://user-gold-cdn.xitu.io/2017/10/6/2f0fb2e7243d5f6f19c2eb8ead022655)

const定義的變量不允許二次修改。還原一下之前的例子,如圖:

![const](https://user-gold-cdn.xitu.io/2017/10/6/4665266d3b082f0275c989d96bf8af51)

是不是再也不用擔(dān)心之前的實(shí)習(xí)生啦,呦?。?!

let和const定義的變量會(huì)形成塊級(jí)作用域。直接上圖,看看:

![塊級(jí)作用域](https://user-gold-cdn.xitu.io/2017/10/6/a670be66e059e8656b71237da148894c)

它們定義的變量不存在變量提升,以及存在暫時(shí)性死區(qū)

這個(gè)問(wèn)題,我想舉個(gè)例子可以更加方便的說(shuō)明。首先,我們來(lái)看一題簡(jiǎn)單的筆試題:

var a = 10;
function hello(){
    console.log(a);
      var a = 11;
      console.log(a);
}
hello();

我想這個(gè)答案不言而喻,是undefined和11。原因:就是第一個(gè)console時(shí),下面定義的變量a被提升了,所以a變成了undefined,第二個(gè)的話,就比較好理解。這個(gè)例子,我想會(huì)給初學(xué)者帶來(lái)不小的麻煩,和當(dāng)初的我一樣哈。

使用let和const就會(huì)不一樣,它們并不存在變量提升,如圖:

函數(shù)的變化——箭頭函數(shù),剩余參數(shù),參數(shù)默認(rèn)值

何為箭頭函數(shù),我們先上例子:

export const addToCart = productId => (dispatch, getState) => {
  if (getState().products.byId[productId].inventory > 0) {
    dispatch(addToCartUnsafe(productId))
  }
}

這是,我從redux例子中摘取的一個(gè)片段,第一感覺(jué)就是『代碼風(fēng)格簡(jiǎn)潔』,整體代碼規(guī)范很好,畢竟是示例代碼么。但是會(huì)讓人難以理解。因此,為了避免以后看不懂的尷尬,還是來(lái)好好聊聊這個(gè)神奇的東西吧。

其實(shí),這個(gè)東西類(lèi)似于python的lambda。但是,它的確特別適合js這門(mén)語(yǔ)言,就一個(gè)字「酷」。它的幾個(gè)規(guī)則:

變量如果只有一個(gè)的時(shí)候,可以省略()

如果是只有一句返回語(yǔ)句時(shí),可以直接省略{return }這一部分

因?yàn)樗旧斫凶鯽rrow,所以每次都必須帶上=>符號(hào)

如果你一開(kāi)始不會(huì)寫(xiě),那就必須得多練習(xí),這樣才能在以后的工作中真正謀求便利。

當(dāng)然咯,它有好處,但是在使用的時(shí)候,也得注意它的禁區(qū)。注意事項(xiàng):

箭頭函數(shù)不能作為構(gòu)造函數(shù)。如圖:

![arrow](https://user-gold-cdn.xitu.io/2017/10/6/80cab1e89e69343aaa393b871f947d23)

箭頭函數(shù)沒(méi)有它自己的this值,箭頭函數(shù)內(nèi)的this值繼承自外圍作用域。如圖:

![arrow](https://user-gold-cdn.xitu.io/2017/10/6/2f4ee91258a2802f53abb504c75a4faf)

箭頭函數(shù)沒(méi)有arguments。這個(gè)我們直接測(cè)試一下就可以了,如圖:

![arrow](https://user-gold-cdn.xitu.io/2017/10/6/95b20121716122fc48bdbec90ac9f6c4)

啥?沒(méi)有arguments,那我如果正好要用到呢?這可咋辦呢?下面再來(lái)說(shuō)個(gè)有意思的改動(dòng)——剩余參數(shù)。

什么叫剩余參數(shù)?別著急,看個(gè)例子就懂了。

const restParam = function(a, ...args){
    console.log(args);
};
restParam(1, 2, 3, 4);   //[2, 3, 4]

這里你會(huì)發(fā)現(xiàn)這個(gè)args變量似乎包含了之后輸入的所有參數(shù),除了a以外。所以,這就是所謂的剩余參數(shù)。其中,運(yùn)用到了一個(gè)這個(gè)符號(hào)。其實(shí)這個(gè)符號(hào)的用處非常的多,ES6中可以將它稱(chēng)為擴(kuò)展符。那么,我們來(lái)看看在箭頭函數(shù)中的運(yùn)用。

當(dāng)然,在使用剩余參數(shù)時(shí),需要注意一個(gè)問(wèn)題,就是剩余參數(shù)設(shè)置的位置。我們先來(lái)看張圖:

所以,在使用剩余參數(shù)時(shí),需要注意的是,將這部分放在所有參數(shù)的最后位置。其實(shí),ES6還帶來(lái)了另一個(gè)參數(shù)的變動(dòng)——默認(rèn)參數(shù)?;蛟S,我們可以先看一下默認(rèn)參數(shù)這個(gè)問(wèn)題,我們之前是怎么處理的。場(chǎng)景:一般在設(shè)置延遲的時(shí)候,都會(huì)有一個(gè)時(shí)間的默認(rèn)值,防止用戶(hù)在沒(méi)有設(shè)置的情況下使用,看看下面的例子:

function defaultParam(time){
    let wait = time || 1000;
      setTimeout(() => {
        //...
    }, wait);
}

這種寫(xiě)法應(yīng)該非常的常見(jiàn),使用的也比較廣泛。但是,使用ES6的語(yǔ)法的話,就會(huì)變成這樣子,例子:

function defaultParam(time = 1000){
    setTimeout(() => {
        //...
    }, time);
}

看上去這樣子的寫(xiě)法,會(huì)使得函數(shù)更加的簡(jiǎn)潔明了。

數(shù)組——解構(gòu)賦值、二進(jìn)制數(shù)組

說(shuō)到解構(gòu)賦值呢?大家千萬(wàn)別誤解為這是數(shù)組的特性。不是的,對(duì)象也能夠滿(mǎn)足。只是覺(jué)得放在這邊來(lái)寫(xiě)會(huì)比較好而已

解構(gòu)賦值這個(gè)新特性,說(shuō)實(shí)話是真的好用。我們可以先來(lái)看一個(gè)復(fù)雜一點(diǎn)的例子:

let [a, b , {name, age}, ...args ] = [1, 2, {name: "zimo", age: 24}, 3, 4];
console.log(a, b, name, age, args); //1, 2, "zimo", 24, [3, 4]

你會(huì)發(fā)現(xiàn)例子中,有一個(gè)特點(diǎn)——對(duì)仗工整。

這是解構(gòu)賦值時(shí),必須要去滿(mǎn)足的條件——想要解構(gòu)的部分,內(nèi)容保持一致。這樣才能保證完美解構(gòu)。對(duì)于解構(gòu)而言,左右兩邊的內(nèi)容長(zhǎng)度不一致,不會(huì)出問(wèn)題。比如,當(dāng)你右邊內(nèi)容多一點(diǎn)的時(shí)候,其實(shí)沒(méi)啥事,你只需要保證你左邊的結(jié)構(gòu)有一部分是你想要的,舉例:

let [a, b, c] = [1, 2, 3, 4, 5];
console.log(a, b, c); //1, 2, 3

這種叫做部分解構(gòu),左邊也是一樣的,對(duì)于多處來(lái)的部分,會(huì)變成undefined。舉例:

let [a,b,c] = [1, 2];
console.log(a, b, c);  //1 2 undefined

解構(gòu)賦值在使用過(guò)程中,也是有需要注意的部分:

必須保證有賦值的過(guò)程。看個(gè)例子:

![解構(gòu)賦值](https://user-gold-cdn.xitu.io/2017/10/6/dd437a39aa760a86119524bfa7de36a2)

你可以看到圖中的例子,多帶帶先聲明了a和b,但是沒(méi)有賦值的過(guò)程,會(huì)報(bào)錯(cuò)。

左邊內(nèi)容部分的結(jié)構(gòu)必須與右邊保持一致。如圖:

這里兩邊的結(jié)構(gòu)沒(méi)有一致,如果是foo,bar的話,是可以正常解構(gòu)的。但是這個(gè)例子的意圖可能是想去解構(gòu)foo中的值,但是寫(xiě)法上有一定的問(wèn)題。

其實(shí),解構(gòu)也有沒(méi)多種玩法:

默認(rèn)值的使用。由于之前說(shuō)過(guò)的部分解構(gòu)的情況出現(xiàn),所以我們?cè)诮鈽?gòu)時(shí),可以使用默認(rèn)值的形式。

let [a, b = 10] = [1];
console.log(a, b);  //1, 10

在這個(gè)例子中b原先是undefined,但是設(shè)置了默認(rèn)值的情況下,undefined的變量會(huì)被賦上默認(rèn)值

函數(shù)變量中使用解構(gòu)。對(duì)于一個(gè)函數(shù)而言,它的參數(shù)也可能會(huì)是數(shù)組或?qū)ο?,這是我們就可以使用解構(gòu)賦值的方式

function destructuring({name, age}){
    console.log(name, age);
}
destructuring({name: "zimo", age: 21}); // zimo 21

解構(gòu)賦值現(xiàn)在被使用的頻率也是非常之大,好好掌握一下也是有必要的。

之后的話,我們可以聊一下二進(jìn)制數(shù)組的概念。

何為二進(jìn)制數(shù)組?其實(shí),我們可以先來(lái)了解一下javascript的數(shù)組。熟悉js的人都知道,其實(shí)js的數(shù)組的性能并不高,它的本質(zhì)是一個(gè)對(duì)象。之所以現(xiàn)在你看到數(shù)組在使用時(shí)速度還可以,是因?yàn)閖s的引擎在處理時(shí),做了不同的優(yōu)化。拿v8引擎舉例的話,對(duì)于內(nèi)部元素類(lèi)型相同的數(shù)組在編譯運(yùn)行的時(shí)候,會(huì)使用c編譯器。如果對(duì)于內(nèi)部元素類(lèi)型不同的時(shí)候,它會(huì)先將數(shù)組分離開(kāi)來(lái),然后再進(jìn)行編譯。具體可以查看深入 JavaScript 數(shù)組:進(jìn)化與性能

所以,我們可以直接了解一下二進(jìn)制數(shù)組的使用。二進(jìn)制數(shù)組可以由Int8Array、Int16Array、Int32Array等形式組成,在整數(shù)方面,可用性較強(qiáng)。

const buffer = new Buffer(100000000);
const arr = new Int8Array(buffer);
console.time("test time");
for(let i = 0; i < arr.length; i++){
    arr[i] = i;
}
console.timeEnd("test time");

其實(shí),現(xiàn)在二進(jìn)制數(shù)組使用的頻率并不多,ES6也僅僅是提出,后續(xù)還會(huì)對(duì)數(shù)組這一塊進(jìn)行一個(gè)更加詳細(xì)的完善。

字符串——模版字符串、startsWith、endsWidth

在ES6中,對(duì)字符串也做了一定的改進(jìn)。先來(lái)聊聊我們的新朋友——模版字符串。其實(shí),在語(yǔ)言中,字符串有多種表示方式:?jiǎn)我?hào)、雙引號(hào)和倒引號(hào)。在javascript中,雙引號(hào)和單引號(hào)都是一樣的,這點(diǎn)與一些靜態(tài)語(yǔ)言不一樣。但是,往往有時(shí)候,對(duì)于字符串的拼接會(huì)使得開(kāi)發(fā)者厭煩。如何解決呢?

ES6帶來(lái)了解決方案——模版字符串。何為模版字符串呢?由倒引號(hào)包裹``,然后使用${}來(lái)包裹變量。我們可以來(lái)實(shí)踐一下

const name="zimo";
const str = `My name is ${name}`;
console.log(str);  //My name is zimo

這樣,我們就可以非常方便的在其中添加變量了?;蛟S,你會(huì)覺(jué)得這樣的拼接,使用普通的方式也可以非常好的完成。但是,在開(kāi)發(fā)過(guò)程中,我們或許會(huì)碰到更佳復(fù)雜的情況,比如說(shuō),我們現(xiàn)在要去創(chuàng)建一個(gè)DOM元素,以及它的內(nèi)部元素。這種情況,通常還會(huì)帶有表達(dá)式。

const width = 100;
const height = 200;
const src = "http://www.example.com/example.png";
const html = `
`;

往往這樣子的元素在手動(dòng)拼接的過(guò)程中,總是會(huì)出錯(cuò),因此,使用模版字符串是一種既「高效」又「簡(jiǎn)潔」的方式。

有了模版字符串,你可以解決非常棘手的問(wèn)題。那么,標(biāo)題中帶有的startsWith和endsWith又是起到什么作用呢?可能你會(huì)使用正則表達(dá)式,那么你就有可能不會(huì)使用到這兩個(gè)API。

按照慣例,還是需要來(lái)介紹一下這兩個(gè)API的。

startsWith:返回值為boolean型,然后去匹配字符串開(kāi)頭的部分,舉個(gè)例子:

const str = "start in the head";
console.log(str.startsWith("start"));  //true
console.log(str.startsWith("head"));  //false

其實(shí),這也是可以使用正則表達(dá)式來(lái)達(dá)到這一目的。還原上例:

const str = "start in the head";
console.log(/^start/.test(str));   //true
console.log(/^head/.test(str));   //false

其實(shí),兩者方式的區(qū)別基本上沒(méi)有,但是正則表達(dá)式的功能更佳的完善。這個(gè)API僅僅在一些場(chǎng)景下起到一定的便捷。比方說(shuō),我們需要去匹配一個(gè)URL的協(xié)議頭是什么時(shí),我們往往需要用到這種方式。例子:

const url = "http://www.example.com";
if(url.startsWith("http")){
    console.log("this is http");
}else if(url.startsWith("https")){
    console.log("this is https");
}else if(url.startsWith("ws")){
    console.log("this is websocket");
}    //this is http

同理,endWith也是一樣的效果。

endsWith:返回值是boolean類(lèi)型,然后去匹配字符串的結(jié)尾。舉個(gè)例子:

const str = "something in the end";
console.log(str.endsWith("end"));   //true
console.log(str.endsWith("something"));  //false

同樣的,它也可以使用正則表達(dá)式來(lái)實(shí)現(xiàn):

const str = "something in the end";
console.log(/end$/.test(str));   //true
console.log(/something$/.test(str));   //false

這種情況的使用場(chǎng)景是,往往我們需要為上傳的文件準(zhǔn)備圖標(biāo),那么我們就可以根據(jù)后綴來(lái)確定圖標(biāo)。

const filename = "upload.jpg";
if(filename.endsWith(".jpg")){
    console.log("this is jpg file");
}else if(filename.endsWith(".png")){
    console.log("this is png file");
}else if(filename.endsWith(".webp")){
    console.log("this is webp file");
}   //this is jpg file

同時(shí),字符串還增加了許許多多的東西,有興趣的,可以自己去翻書(shū)本詳細(xì)的了解

Iterator和for...of

Iterator的概念是迭代器。在ES6中,終于正式的添加了這個(gè)屬性。迭代器,主要是一個(gè)集合類(lèi)元素的遍歷機(jī)制。何為集合類(lèi)元素?最常見(jiàn)的就是數(shù)組,還有對(duì)象。迭代器可以幫助開(kāi)發(fā)者完成遍歷集合的過(guò)程。最開(kāi)始javascript并沒(méi)有設(shè)置接口,來(lái)自定義迭代器,但是從ES6開(kāi)始,我們可以自定義迭代器了。在自定義迭代器之前,我們要清楚迭代器的作用有哪些:

為各種數(shù)據(jù)結(jié)構(gòu)提供一個(gè)統(tǒng)一的、簡(jiǎn)便的訪問(wèn)接口

使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列

在ES6中,迭代器主要供我們之后要講述的for...of服務(wù)

迭代器,往往就是一個(gè)指針對(duì)象,不斷調(diào)用,然后不斷地指向下一個(gè)對(duì)象的過(guò)程,直到結(jié)束。ES6中,我們可以創(chuàng)建一個(gè)指針對(duì)象,然后調(diào)用next的函數(shù),使得指針對(duì)象向下移動(dòng)。同時(shí),next函數(shù)會(huì)返回value和done,確定是否到達(dá)末尾。

同時(shí),ES6還提供了Iterator接口——Symbol.iterator。首先,我們來(lái)看一下具備原生接口的集合類(lèi)——數(shù)組,類(lèi)數(shù)組對(duì)象、Set和Map。這樣我們就可以直接調(diào)用它的接口來(lái)進(jìn)行循環(huán):

let arr = ["my", "name", "is", "iterator"];
let iter = arr[Symbol.iterator]();
console.log(iter.next());   //{ value: "my", done: false}
console.log(iter.next());   //{ value: "name", done: false}
console.log(iter.next());   //{ value: "is", done: false}

同時(shí),定義iterator接口的數(shù)據(jù)結(jié)構(gòu)可以輕松的使用for...of進(jìn)行值的遍歷

let arr = ["I", "has", "iterator"];
for(let item of arr){
    console.log(item);
}   //"I", "has", "iterator"

但是,如果沒(méi)有定義iterator接口的數(shù)據(jù)結(jié)構(gòu)就沒(méi)有辦法使用這種方式進(jìn)行遍歷,如圖:

這時(shí),我們又該如何呢?其實(shí),針對(duì)一些可迭代的數(shù)據(jù)結(jié)構(gòu),我們是可以自定義迭代器的,例如:

let iteratorObj = {
    0: "a",
      1: "b",
      2: "c",
      length: 3,
     [Symbol.iterator]: Array.prototype[Symbol.iterator]
}
for(let item of iteratorObj){
    console.log(item);
}  // "a", "b", "c"

迭代器是一個(gè)非常實(shí)用的東西,不妨你也可以試試,同時(shí)去改善你的代碼。

Generator和Promise

其實(shí),這兩個(gè)是比較難以理解的東西。如果只是粗淺的了解一下,還是有許多的新東西的。在ES6中,引入了generator和promise兩個(gè)概念??赡茉谶@之前,你已經(jīng)使用過(guò)了,通過(guò)其他的類(lèi)庫(kù)實(shí)現(xiàn)的。那么,其實(shí)ES6中的新概念也是差不多的,只是標(biāo)準(zhǔn)化了而已。

generator,叫做生成器??梢哉f(shuō)與iterator有點(diǎn)相似,同樣是通過(guò)next函數(shù),來(lái)一步步往下執(zhí)行的。同時(shí),它的定義時(shí),所使用的是function*的標(biāo)識(shí)符。還具備yield這個(gè)操作符,可以實(shí)現(xiàn)逐步逐步向下執(zhí)行。我們來(lái)看個(gè)例子:

function* generator(){
  yield 1;
  yield 2;
  yield 3;
};

let generate = generator();

console.log(generate.next());  //{value: 1, done: false}
console.log(generate.next());  //{value: 2, done: false}
console.log(generate.next());  //{value: 3, done: true}
console.log(generate.next());  //{value: undefined, done: true}

這樣子看起來(lái),似乎就是迭代器的步驟。其實(shí),iterator的接口,可以定義成這樣子的形式。但是,generator的作用不僅僅如此。它就像一個(gè)狀態(tài)機(jī),可以在上一個(gè)狀態(tài)到下一個(gè)狀態(tài)之間進(jìn)行切換。而一旦遇到y(tǒng)ield部分,則可以表示當(dāng)前是可以步驟的暫停。需要等到調(diào)用next方法才能進(jìn)行下一步驟。同時(shí),我們還可以使用上一步的結(jié)果值,進(jìn)行下一步的運(yùn)算。示例:

function* generator(){
  yield 1;
  let value = yield 2;
  yield 3 + value;
};

let generate = generator();

let value1 = generate.next();
let value2 = generate.next();
let value3 = generate.next(value2.value);
console.log(value1);  //{value: 1, done: false}
console.log(value2);  //{value: 2, done: false}
console.log(value3);  //{value: 5, done: true}

這樣的話,就可以將value作為你第三步的參數(shù)值,進(jìn)行使用。

之前說(shuō)過(guò),generator的next是需要自己調(diào)用的。但是,我們?nèi)绾问顾约鹤詣?dòng)調(diào)用呢。我們可以使用for...of來(lái)自動(dòng)調(diào)用next,就像迭代器一樣。示例:

function* generator(){
  yield 1;
  yield 2;
  yield 3;
};
for(let value of generator()){
  console.log(value);
}   //1, 2, 3

其實(shí),之前所講的只是generator的基本使用。generator主要被使用在異步編程領(lǐng)域。因?yàn)槲覀冎八v的特性,非常適合在異步編程中使用。當(dāng)然了,我們也需要去提一下promise這個(gè)異步編程的功臣。

Promise,翻譯過(guò)來(lái)叫做承諾。我們可以理解為一種約定。大家都知道異步編程的時(shí)候,我們一般會(huì)使用到回調(diào)函數(shù)這個(gè)東西。但是,回調(diào)函數(shù)會(huì)導(dǎo)致的問(wèn)題,也非常的明顯。示例:

callback1(function(data){
    //...
      callback2(function(data1){
        const prevData = data;
          //...
          callback3(function(){
            //...
              callback4(function(){
                //...
            });
        });
    });
});

回調(diào)函數(shù),寫(xiě)多了之后我們會(huì)發(fā)現(xiàn),這個(gè)倒金字塔會(huì)越來(lái)越深,而我們會(huì)越來(lái)越難以管理。

這時(shí),或許promise會(huì)起到一定的作用。試想一下,為什么這幾個(gè)回調(diào)函數(shù)都能在另一個(gè)回調(diào)函數(shù)之外進(jìn)行?主要原因:

每個(gè)回調(diào)函數(shù),都會(huì)無(wú)法確定另一個(gè)回調(diào)函數(shù)會(huì)在何時(shí)會(huì)被調(diào)用,因?yàn)檫@個(gè)控制權(quán)不在當(dāng)前這個(gè)程序之中。

每個(gè)回調(diào)函數(shù),都或多或少的依賴(lài)于上一個(gè)回調(diào)函數(shù)執(zhí)行的時(shí)間和數(shù)據(jù)

基于這兩點(diǎn),我們就會(huì)發(fā)現(xiàn),一旦你需要這樣去編寫(xiě)代碼,就必須保證你的上一個(gè)回調(diào)函數(shù)在下一個(gè)回調(diào)函數(shù)之前進(jìn)行。我們還可以發(fā)現(xiàn),它們之間缺乏一種約定,就是一旦上一個(gè)發(fā)生了,無(wú)論是正確還是錯(cuò)誤,都會(huì)通知對(duì)應(yīng)的回調(diào)函數(shù)的約定。

Promise,或許就是起到了這樣的一種作用。它具備三種狀態(tài):pending、resolved、rejected。它們之間分別對(duì)應(yīng):正在進(jìn)行、已解決、已拒絕等三種結(jié)果。一個(gè)回調(diào)函數(shù)會(huì)開(kāi)始從pending狀態(tài),它會(huì)向resolved和rejected的兩者之一進(jìn)行轉(zhuǎn)換。而且這種轉(zhuǎn)換是不可變的,即一旦你從pending狀態(tài)轉(zhuǎn)變到resolved狀態(tài),就不可以再變到rejected狀態(tài)去了。

然后,promise會(huì)有一個(gè)then函數(shù),可以向下傳遞之前回調(diào)函數(shù)返回的結(jié)果值。我們可以寫(xiě)個(gè)promise示例:

new Promise((resolved, rejected) => {
  resolved(1);
}).then(data => {
  console.log(data);
}, err => {
  console.log(err);
}).catch(err => {
  console.log(err);
});  // 1

其實(shí),只需要記住這樣子的一種形式,就可以寫(xiě)好promise。Promise是一個(gè)比較容易書(shū)寫(xiě)的東西。因?yàn)樗男问奖容^單一,而且現(xiàn)在有許多封裝的比較好的異步請(qǐng)求庫(kù),都帶有Promise的屬性,例如axios。

Promise,還帶有其他的一些API,上面我們也使用到了一個(gè)。

catch:用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。主要是我們之前說(shuō)過(guò)Promise有個(gè)不可變的特性,所以,一旦這一個(gè)過(guò)程中發(fā)生錯(cuò)誤,但是狀態(tài)無(wú)法轉(zhuǎn)變,只能在下一個(gè)流程中去捕獲這個(gè)錯(cuò)誤。因此,為了預(yù)防最后一個(gè)流程發(fā)生錯(cuò)誤,需要在最后使用catch去捕獲最后一個(gè)流程中的錯(cuò)誤。

all:用于將多個(gè)Promise實(shí)例包裝成一個(gè)新的Promise實(shí)例。

這個(gè)函數(shù)需要其中所有的Promise實(shí)例都變成Fulfilled時(shí),才會(huì)將結(jié)果包裝成一個(gè)數(shù)組傳遞給下一個(gè)Promise。

如果其中有一個(gè)Promise實(shí)例變成Rejected時(shí),就會(huì)將第一個(gè)Rejected的結(jié)果傳遞給下一個(gè)Promise

race:也是用于將多個(gè)Promise實(shí)例包裝成一個(gè)新的Promise實(shí)例。但是這個(gè)函數(shù)有所不同

如果這個(gè)函數(shù)中,有一個(gè)Promise變成Fulfilled時(shí),它就會(huì)將結(jié)果傳遞給下一個(gè)Promise

resolve:它會(huì)將一個(gè)當(dāng)前對(duì)象轉(zhuǎn)化為Promise對(duì)象

reject:返回一個(gè)出錯(cuò)的Promise對(duì)象

Promise可以和之前所講的Generator一起使用,我們可以看一下使用場(chǎng)景:

通過(guò)Generator函數(shù)來(lái)管理流程,遇到異步操作,就使用Promise進(jìn)行處理。

function usePromise(){
  return new Promise(resolve => {
    resolve("my name is promise");
  });
}

function* generator(){
  try{
    let item = yield usePromise();
    console.log(item);
  }catch(err){
    console.log(err);
  }
}

let generate = generator();
generate.next().value.then(data => {
  console.log(data);
}, err => {
  console.log(err);
}).catch(err => {
  console.log(err);
});   //my name is promise

或許,你還可以寫(xiě)出更加復(fù)雜的程序。

Class和extends

最后要聊的一個(gè)主題就是class。相信抱怨javascript沒(méi)有類(lèi)的特性數(shù)不勝數(shù)。同時(shí),還需要去了解js的類(lèi)繼承式概念。那么,ES6也帶來(lái)了我們最歡迎的class module部分。我們就不介紹之前我們是如果去構(gòu)建對(duì)象的了(好像是構(gòu)造函數(shù))。

那么,我們可以來(lái)看一下,ES6給我?guī)?lái)的新變化:

class Animal{
  constructor(name){
      this.name = name;
  }

  sayName(){
      return this.name;
  }
}

const animal = new Animal("dog");
console.log(animal.sayName());  // "dog"

似乎這樣子的形式比之前的構(gòu)造函數(shù)的方式強(qiáng)對(duì)了。我們可以理解一下這個(gè)結(jié)構(gòu):

其內(nèi)部的constructor:指向的就是整個(gè)類(lèi)的constructor

其內(nèi)部的函數(shù):這些函數(shù)的定義在類(lèi)的原型上面

因此,上面那個(gè)其實(shí)可以寫(xiě)成原先的:

function Animal(name){
    this.name = name;
}
Animal.prototype.sayName = function(){
    return this.name;
}

其實(shí),就是class在ES6中得到了封裝,可以使得現(xiàn)在的方式更加的優(yōu)美。

之后,我們簡(jiǎn)單了解一下繼承這個(gè)概念吧。

任何的東西,都是需要繼承的。因?yàn)槲覀儾豢赡芏际菑念^去寫(xiě)這個(gè)類(lèi)。往往是在原有類(lèi)的基礎(chǔ)之上,對(duì)它進(jìn)行完善。在ES6之前,我們可能對(duì)構(gòu)造函數(shù)完成的是組合式繼承。示例:

function Animal(name){
  this.name = name;
}
Animal.prototype.sayName = function(){
  return this.name;
}
function Dog(name, barking){
  Animal.call(this, name);
  this.barking = barking;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.makeBarking = function(){
  return this.barking;
}
const dog = new Dog("zimo", "汪汪汪");
console.log(dog.makeBarking());   //汪汪汪
console.log(dog.sayName());  //zimo

這樣子的組合式繼承書(shū)寫(xiě)起來(lái),比較麻煩,需要重新去對(duì)每個(gè)元素設(shè)置,然后還要重新定義新類(lèi)的原型。那么,我們可以來(lái)看一下ES6對(duì)于繼承的封裝:

class Animal{
    constructor(name){
        this.name = name;
    }
  
      sayName(){
        return this.name;
    }
}
class Dog extends Animal{
    constructor(name, barking){
        super(name);
          this.barking = barking;
    }
      
      makeBarking(){
        return this.barking;
    }
}

這樣子,就可以輕松的完成之前的組合式繼承步驟了。如果你對(duì)extends的封裝感興趣的話,不妨看一下這篇文章javascript之模擬類(lèi)繼承

總結(jié)

在這里ES6的內(nèi)容只是總結(jié)了部分,大致可以分為這么幾個(gè)部分:

變量定義——let和const

函數(shù)的變化——箭頭函數(shù)、剩余參數(shù)

數(shù)組的變動(dòng)——解構(gòu),展開(kāi)符

字符串——模版字符串、startsWith、endsWith

Iterator和for...of

Generator和Promise

Class和extends

希望,你可以從這些內(nèi)容中對(duì)ES6多一些了解,同時(shí),如果你還想深入ES6進(jìn)行了解的話,最直接的方式就是看書(shū)。希望你的代碼寫(xiě)的越來(lái)越優(yōu)雅。

如果你對(duì)我寫(xiě)的有疑問(wèn),可以評(píng)論,如我寫(xiě)的有錯(cuò)誤,歡迎指正。你喜歡我的博客,請(qǐng)給我關(guān)注Star~呦。大家一起總結(jié)一起進(jìn)步。歡迎關(guān)注我的github博客

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88868.html

相關(guān)文章

  • 全棧開(kāi)發(fā)自學(xué)路線

    摘要:前言這里筑夢(mèng)師是一名正在努力學(xué)習(xí)的開(kāi)發(fā)工程師目前致力于全棧方向的學(xué)習(xí)希望可以和大家一起交流技術(shù)共同進(jìn)步用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程個(gè)人學(xué)習(xí)方法分享本文目錄更新說(shuō)明目錄學(xué)習(xí)方法學(xué)習(xí)態(tài)度全棧開(kāi)發(fā)學(xué)習(xí)路線很長(zhǎng)知識(shí)拓展很長(zhǎng)在這里收取很多人的建議以后決 前言 這里筑夢(mèng)師,是一名正在努力學(xué)習(xí)的iOS開(kāi)發(fā)工程師,目前致力于全棧方向的學(xué)習(xí),希望可以和大家一起交流技術(shù),共同進(jìn)步,用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程...

    galaxy_robot 評(píng)論0 收藏0
  • 全棧開(kāi)發(fā)自學(xué)路線

    摘要:前言這里筑夢(mèng)師是一名正在努力學(xué)習(xí)的開(kāi)發(fā)工程師目前致力于全棧方向的學(xué)習(xí)希望可以和大家一起交流技術(shù)共同進(jìn)步用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程個(gè)人學(xué)習(xí)方法分享本文目錄更新說(shuō)明目錄學(xué)習(xí)方法學(xué)習(xí)態(tài)度全棧開(kāi)發(fā)學(xué)習(xí)路線很長(zhǎng)知識(shí)拓展很長(zhǎng)在這里收取很多人的建議以后決 前言 這里筑夢(mèng)師,是一名正在努力學(xué)習(xí)的iOS開(kāi)發(fā)工程師,目前致力于全棧方向的學(xué)習(xí),希望可以和大家一起交流技術(shù),共同進(jìn)步,用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程...

    Scorpion 評(píng)論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<