1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        2021年,快速了解 ES2022 新特性(一)

        共 2628字,需瀏覽 6分鐘

         ·

        2021-11-09 22:13

        大廠技術(shù)??高級前端??Node進(jìn)階

        點(diǎn)擊上方?程序員成長指北,關(guān)注公眾號

        回復(fù)1,加入高級Node交流群


        作為一個后端的菜菜,其實應(yīng)該多寫點(diǎn)后端的東西,奈何同學(xué)們都喜歡看點(diǎn)前端的文章。這就沒法子了??,前兩天看到掘金群里有位同學(xué)不知道在哪兒看ES的新特性和ES規(guī)范與新特性的對應(yīng)關(guān)系。我覺得我的機(jī)會來了??,忙了兩天,今天抽點(diǎn)時間給大家科普一下,順便講講 ES2016-ES2022 到底有啥內(nèi)容,順便復(fù)習(xí)一下,加深印象。

        ES是啥?

        ES的全稱是ECMAScript,由 ECMA國際[3] (前身為歐洲計算機(jī)制造商協(xié)會)在標(biāo)準(zhǔn) ECMA-262[4] 中定義的腳本語言規(guī)范,從2015年起,每年一個版本,到 ES2022 已經(jīng)是第十三個版本了。我們常用的 JavaScript 就是 ECMA-262[5] 標(biāo)準(zhǔn)的實現(xiàn)和拓展?,F(xiàn)在我直接貼一個官網(wǎng)的地址 ECMAScript[6] 吧,詳細(xì)的內(nèi)容大家可以直接查看官網(wǎng)的介紹。我就不過多介紹這個東西了。水字?jǐn)?shù)沒必要。。。??

        盡管 ES2022 的還沒有正式發(fā)布,但是提案已經(jīng)完成,板上釘釘。下面我就按照大概的情況列一下各個ES版本提案的全稱、發(fā)布年份、縮寫信息等,這樣大家就不會迷惑ES的命名了。

        全稱發(fā)布年份縮寫 / 簡稱
        ECMAScript 20152015ES2015 / ES6
        ECMAScript 20162016ES2016 / ES7
        ECMAScript 20172017ES2017 / ES8
        ECMAScript 20182018ES2018 / ES9
        ECMAScript 20192019ES2019 / ES10
        ECMAScript 20202020ES2020 / ES11
        ECMAScript 20212021ES2021 / ES12
        ECMAScript 20222022ES2022 / ES13

        有的同學(xué)可能會有這樣的疑問,為啥 ES2015 對應(yīng)的是 ES6 ,而不是 ES5 呢? 這里說明一下,這兩個數(shù)字不是同一個東西,2015 代表的是發(fā)布的日期,而 6 表示的是ECMAScript語言規(guī)范的第幾個版本。這樣不懂的同學(xué)可能就明白了,再回頭一看上面的表格,這樣印象就更加深刻了。

        ES2016 - ES2022的特性

        騷話不多說,下面我們直接開始吧。我會將 ES2016 - ES2022 的內(nèi)容分成一段段舉例演示,內(nèi)容主要以 Github已完成 提案[7] 上的順序講解。(PS: 沒有 ES2015 / ES6 ,直接 ES2016 / ES7 起步)

        ES2016 / ES7

        Array.prototype.includes 數(shù)組是否包含某個元素

        這個特性很多小伙伴肯定都用過,這個主要的作用是查找一個元素是否在數(shù)組中。在這個方法沒出來之前,偷懶同學(xué)可能是通過數(shù)組的 indexOf 方法來做校驗的

        [1,?2,?3].indexOf(1)?>=?0

        //?結(jié)果:?true
        復(fù)制代碼

        正常情況下,indexOf 方法并沒有啥毛病,但是這個方法存在一個漏洞,當(dāng)需要查看的元素是 NaN 時,這個 indexOf 方法將不能夠準(zhǔn)確的判斷出元素是否被包含在數(shù)組中

        [1,?2,?NaN].indexOf(NaN)?>=?0

        //?結(jié)果:?false
        復(fù)制代碼

        另外一個問題是,indexOf 這個方法主要想表明的是一個元素在數(shù)組中的 索引位置 而不是確定一個元素是否包含在數(shù)組中,所以勤快的同學(xué)一般會通過手寫一個循環(huán)方法來處理這個問題,但是引用這個方法又比較麻煩,直接套在原型上?不敢不敢。。。

        function?contains(array,?val)?{
        ????for?(var?i?=?0;?i?????????if?(array[i]?===?val)?{
        ????????????return?true;
        ????????}
        ????}
        ????return?false;
        }
        復(fù)制代碼

        現(xiàn)在我們有了 includes 方法,上述的問題都將解決,并且更加好使,我們來測試一下以下代碼,大家可以腦補(bǔ)一下下面的結(jié)果

        console.log([1,?2,?3].includes(2)?===?true);
        console.log([1,?2,?3].includes(4)?===?false);
        console.log([1,?2,?NaN].includes(NaN)?===?true);

        console.log([1,?2,?-0].includes(+0)?===?true);
        console.log([1,?2,?+0].includes(-0)?===?true);

        console.log(["a",?"b",?"c"].includes("a")?===?true);
        console.log(["a",?"b",?"c"].includes("a",?1)?===?false);
        復(fù)制代碼

        我們現(xiàn)在公布答案,上面的七個結(jié)果均為 true 。毋庸置疑。。。

        Exponentiation operator 冪運(yùn)算

        這個沒有啥好講的,直接看下面的代碼片段就明白了

        let?squared?=?2?**?2;
        //?same?as:?2?*?2

        let?cubed?=?2?**?3;
        //?same?as:?2?*?2?*?2

        let?a?=?2;
        a?**=?2;
        //?same?as:?a?=?a?*?a;

        let?b?=?3;
        b?**=?3;
        //?same?as:?b?=?b?*?b?*?b;
        復(fù)制代碼

        ES2017 / ES8

        Object.values / Object.entries 對象值、對象對

        這個也沒啥好說的,Object.values 方法返回一個給定對象自身的所有可枚舉屬性值的數(shù)組,值的順序與使用for...in循環(huán)的順序相同(區(qū)別在于 for-in 循環(huán)枚舉原型鏈中的屬性),看代碼

        let?point?=?{x:?12,?y:?6};
        Object.values(point);

        //?結(jié)果:?[12,?6]
        復(fù)制代碼

        Object.entries 方法返回一個給定對象自身可枚舉屬性的鍵值對數(shù)組,其排列與使用 for...in 循環(huán)遍歷該對象時返回的順序一致(區(qū)別在于 for-in 循環(huán)還會枚舉原型鏈中的屬性)。

        聽起來有點(diǎn)繞,咱們直接看代碼

        let?point?=?{x:?12,?y:?6};
        Object.entries(point);

        //?結(jié)果:?[["x",?12],?["y",?6]]
        復(fù)制代碼

        字符串也同樣ok

        Object.entries("hello?world");

        //?結(jié)果:?[["0","h"],["1","e"],["2","l"],["3","l"],["4","o"],["5","?"],["6","w"],["7","o"],["8","r"],["9","l"],["10","d"]]
        復(fù)制代碼

        來試試順序

        let?object?=?{
        ????3:?"z",
        ????1:?"x",
        ????2:?"y",
        ????z:?3,
        ????x:?1,
        ????y:?2
        };

        for?(var?key?in?object)?{
        ????console.log(key);
        }
        //?1
        //?2
        //?3
        //?z
        //?x
        //?y

        Object.entries(object);

        //?結(jié)果:?[["1","x"],["2","y"],["3","z"],["z",3],["x",1],["y",2]]
        復(fù)制代碼

        我們可以看到,輸出結(jié)果和上面我們的方法描述一致(其排列與使用 for...in 循環(huán)遍歷該對象時返回的順序一致)。同時,這兒還有個隱藏的 bufffor...in 會對數(shù)字的類型的 key 升序放在前面,不相信的同學(xué)自己也可以嘗試一下哦。

        String.prototype.padStart / String.prototype.padEnd 填充字符串

        這兩個方法還是比較常見的,我可以指定一個字符最大的寬度,當(dāng)字符串超過最大長度則截斷替換字符,保留左邊(padStart)或者右邊(padEnd)的內(nèi)容當(dāng)字符串寬度沒有達(dá)到的時候,將會在開始(padStart )或者結(jié)尾(padEnd )填充指定的字符,填充字符未指定默認(rèn)是一個 空格(U+0020) ,它主要用來格式化字符串,當(dāng)然你也可以把它玩兒出花來。我們先來看一下定義

        interface?String?{
        ????/**
        ?????*?用給定字符串(可能重復(fù))填充當(dāng)前字符串,以使生成的字符串達(dá)到給定長度。填充從當(dāng)前字符串的開始(左)開始應(yīng)用。
        ?????*
        ?????*?@param maxLength 填充當(dāng)前字符串后所得字符串的長度。如果此參數(shù)小于當(dāng)前字符串的長度,則當(dāng)前字符串將按原樣返回。
        ?????*
        ?????*?@param fillString 用于填充當(dāng)前字符串的字符串。如果此字符串太長,將截斷它,并應(yīng)用最左邊的部分。參數(shù)的默認(rèn)值為'?'(U+0020)。
        ?????*/

        ????padStart(maxLength:?number,?fillString?:?string):?string;

        ????/**
        ?????*?用給定字符串(可能重復(fù))填充當(dāng)前字符串,以使生成的字符串達(dá)到給定長度。從當(dāng)前字符串的末尾(右側(cè))應(yīng)用填充。
        ?????*
        ?????*?@param maxLength 填充當(dāng)前字符串后所得字符串的長度。如果此參數(shù)小于當(dāng)前字符串的長度,則當(dāng)前字符串將按原樣返回。
        ?????*
        ?????*?@param fillString 用于填充當(dāng)前字符串的字符串。如果此字符串太長,將截斷它,并應(yīng)用最左邊的部分。參數(shù)的默認(rèn)值為'?'(U+0020)。
        ?????*/

        ????padEnd(maxLength:?number,?fillString?:?string):?string;
        }
        復(fù)制代碼

        有的同學(xué)可能對上面的超出長度的截斷的含義比較模糊,下面我們直接上手,看下輸出就明白了

        'foo'.padStart(5)
        //?結(jié)果:?'??foo'
        'foo'.padStart(5,?'-')
        //?結(jié)果:?'--foo'
        'foo'.padStart(5,?'xyz')
        //?結(jié)果:?'xyfoo'?(超出長度,'z'?字符被截斷去掉了,保留了左邊部分的內(nèi)容)
        'bar'.padEnd(5)
        //?結(jié)果:?'bar??'
        'bar'.padEnd(5,?'-')
        //?結(jié)果:?'bar--'
        'bar'.padEnd(5,?'xyz')
        //?結(jié)果:?'barxy'?(超出長度,'z'?字符被截斷去掉了,保留了左邊部分的內(nèi)容)

        //?原字符串長度超出最大字符串長度情況下
        'foo'.padStart(2,?'xyz')
        //?結(jié)果:?'foo'
        'foo'.padStart(2,?'xyz')
        //?結(jié)果:?'foo'
        復(fù)制代碼

        Object.getOwnPropertyDescriptors 獲取自身屬性描述符

        這個方法我們可以根據(jù)方法含義來理解,那就是獲取自身屬性的描述符。它常常配合 Object.create() 這個方法,來實現(xiàn)拷貝對象屬性/對象屬性特性以及原型。在理解這個方法之前,我們得知道啥是屬性描述符。我們先定義一個對象打印一手,直接獲取了對象的屬性的描述符

        let?point?=?{
        ????x:?12,
        ????y:?16,
        ????move({x,?y})?{
        ????????this.x?=?x;
        ????????this.y?=?y;
        ????}
        }
        Object.getOwnPropertyDescriptors(point);
        //?{
        //?????x:?{
        //?????????configurable:?true,
        //?????????enumerable:?true,
        //?????????value:?12,
        //?????????writable:?true,
        //?????????[[Prototype]]:?Object
        //?????},?
        //?????y:?{
        //?????????configurable:?true,
        //?????????enumerable:?true,
        //?????????value:?16,
        //?????????writable:?true,?
        //?????????[[Prototype]]:?Object
        //?????},
        //?????move:?{
        //?????????configurable:?true,
        //?????????enumerable:?true,
        //?????????value:?f?move({x,y}),
        //?????????writable:?true,?
        //?????????[[Prototype]]:?Object
        //?????},
        //?????[[Prototype]]:?Object
        //?}

        let?c?=?{}
        Object.getOwnPropertyDescriptors(c);
        //?{}
        復(fù)制代碼

        我們從上面的結(jié)果中,可以發(fā)現(xiàn):如果對象為空,那么獲取到的描述就是個空對象,如果有屬性或者方法,會對每個屬性進(jìn)行描述,包含

        • configurable: 當(dāng)且僅當(dāng)該屬性的 configurable 鍵值為 true 時,該屬性的描述符才能夠被改變,同時該屬性也能從對應(yīng)的對象上被刪除。默認(rèn)為 false
        • enumerable: 當(dāng)且僅當(dāng)該屬性的 enumerable 鍵值為 true 時,該屬性才會出現(xiàn)在對象的枚舉屬性中。默認(rèn)為 false。
        • value: 該屬性對應(yīng)的值??梢允侨魏斡行У?JavaScript 值( 數(shù)值 , 對象 , 函數(shù) 等)。默認(rèn)為 undefined。
        • writable: 當(dāng)且僅當(dāng)該屬性的 writable 鍵值為 true 時,屬性的值,也就是上面的 value,才能被賦值運(yùn)算符改變。默認(rèn)為 false。

        詳情我們可以在 Object.defineProperty\(\)[8] 這兒看到,這里的屬性描述符實際上是給 Object.defineProperty\(\)[9] 的第三個參數(shù)用的。從上面的例子中,我們可以看出,我們直接定義一個對象 point ,并且直接設(shè)置屬性方法,對象屬性默認(rèn) configurable , enumerablewritable 設(shè)置為 true 。

        我們現(xiàn)在給上面的例子再修改一下,加深理解。我們先遍歷打印一下 pointkey

        for?(var?key?in?point)?{
        ????console.log(key);
        }
        //?x
        //?y
        //?move
        復(fù)制代碼

        接著使用 Object.defineProperty\(\)[10] 方法修改一下 pointmove 方法的描述符

        Object.defineProperty(point,?'move',?{
        ????enumerable:?false
        });
        for?(var?key?in?point)?{
        ????console.log(key);
        }
        //?x
        //?y
        復(fù)制代碼

        我們可以看到 move 這個方法在 for..in 中已經(jīng)沒有打印名稱了。我們用 Object.getOwnPropertyDescriptor\(\)[11] 這個 老方法 再看看 move 的屬性描述符

        Object.getOwnPropertyDescriptor(point,?'move');
        //{
        //????configurable:?true,
        //????enumerable:?false,
        //????value:?f?move({x,y}),
        //????writable:?true,?
        //????[[Prototype]]:?Object
        //}
        復(fù)制代碼

        符合我們的預(yù)期。大家看明白了屬性描述符,那對這個新增的方法就能理解的明明白白了

        Async functions 異步方法

        這個感覺沒有啥好寫的,懂得都懂。asyncawait 相當(dāng)于一個語法糖,被 async 標(biāo)記的方法將會返回一個 Promise 對象。我們可以在一個 async 標(biāo)記的方法中使用 await 一個 Promise 對象,當(dāng) Promise 結(jié)束之后才執(zhí)行下一語句,這讓我們可以在 async 標(biāo)記的方法中用同步的方法來書寫異步的 Promise 。我們簡單舉一個例子

        async?function?a()?{
        ????return?"a";
        }
        function?b()?{
        ????return?new?Promise((resolve,?reject)?=>?{
        ????????setTimeout(()?=>?{
        ????????????resolve("b");
        ????????},?3000);
        ????});
        }
        async?function?c()?{
        ????return?"c";
        }
        async?function?d()?{
        ????let?a?=?await?a();
        ????console.log(a);
        ????let?b?=?await?b();
        ????console.log(b);
        ????let?c?=?await?c();
        ????console.log(c);
        }
        console.log(d())

        //?結(jié)果:
        //?Promise?{??}?`async`?標(biāo)記的方法返回了一個?`Promise`?對象
        //?a
        //?b??等待三秒之后繼續(xù)輸出后續(xù)內(nèi)容
        //?c

        復(fù)制代碼

        異步的方法同步的方式寫,看起來很美好,但實際使用中還是有一點(diǎn)點(diǎn)問題。我之前寫過一篇 JS中優(yōu)雅的使用async await[12] ,有興趣的小伙伴可以去瞅瞅。

        Shared memory and atomics 共享內(nèi)存和原子

        這個是給瀏覽器的規(guī)范,我們可以通過 SharedArrayBufferAtomics 增強(qiáng) js 的并行能力,想要了解的同學(xué)可以翻看 SharedArrayBuffer[13]Atomics[14] ,因為出現(xiàn)的場景很少,我就不細(xì)講了。加油啊各位。

        總結(jié)

        文章到這兒暫時告一段落,我一開始膨脹了,文章最開始的標(biāo)題是 一文快速了解ES2016 \- ES2022新特性 。但是寫下來,照我這個講解程度,光 ES7ES8 的篇幅就已經(jīng)很長了,所以我現(xiàn)在打算將 ES2016 \- ES2022 的新特性拆分成多篇來寫,目的呢,為了更好的讓大家理解這些內(nèi)容(才不是呢??),給大家和我自己一點(diǎn)余地。嘻嘻

        關(guān)于本文

        作者:盡管如此世界依然美麗

        https://juejin.cn/post/7021183043679289352

        Node 社群


        我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。


        ???“分享、點(diǎn)贊、在看” 支持一波??

        瀏覽 52
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            色情大片AAAAAA视频人与 | 中文字幕一区二区三区四区五区人 | 午夜久久精品 | 全黄做爰100分钟视频 | 亚洲无码五区 | 日韩天天操 | 天天看天天碰天天摸 | 婷婷丁香狼人久久大香线蕉 | 精品黄色小说 | 日韩无码蜜桃 |