關(guān)于es6-es11中新特性的一些想法

參考規(guī)范:https://tc39.es/ecma262/

Es6(es2015)

概述

  1. 增強(qiáng)功能 包括模塊叛本、類聲明弦赖、詞法塊作用域喳挑、迭代器和生成器味赃,異步編程掀抹,解構(gòu)模式以及適當(dāng)?shù)奈膊空{(diào)用虐拓。
  2. 內(nèi)置庫(kù)的擴(kuò)展 支持?jǐn)?shù)據(jù)抽象心俗,包括Map, 集合Set, 以及二進(jìn)制數(shù)值的數(shù)組。對(duì)象以及數(shù)組功能的擴(kuò)展蓉驹。

第六版的重點(diǎn)開發(fā)工作始于2009年城榛,并于2015年6月通過,是經(jīng)過了15年的努力的結(jié)果态兴。作為常規(guī)版本存在狠持,對(duì)增量語言和庫(kù)增強(qiáng)功能提供了基礎(chǔ)。

因?yàn)镋s6已經(jīng)是大家耳熟能詳?shù)恼叭螅赃@里就不花篇幅了描述了喘垂,詳細(xì)見:es6教程

Es7(es2016)

在es6提出后,TC-39決議認(rèn)為耗時(shí)過長(zhǎng)不利于可持續(xù)發(fā)展绍撞,于是將發(fā)布周期轉(zhuǎn)換為每年發(fā)布一個(gè)版本正勒,以確保新的語言特性能夠更快的發(fā)展。

  1. Array.prototype.includes
  2. 新的指數(shù)運(yùn)算符 **
  3. 新的語法錯(cuò)誤

因?yàn)槊磕甓紩?huì)出一個(gè)版本傻铣,所以改動(dòng)不會(huì)像es6一樣那么大章贞,一個(gè)個(gè)來看一下:

  1. Array.prototype.includes

    規(guī)定: 其實(shí)在es6中已經(jīng)有 Array.prototype.includes 了, 只不過仍未完善非洲,所以出現(xiàn)在了es7的版本中鸭限。

    兩個(gè)參數(shù):第一個(gè)要搜索的值蜕径,第二個(gè)開始搜索的索引位置(可選,默認(rèn)為0)败京。

    返回值:找到返回true兜喻,找不到返回false。

    let nums = [7, 8, 9];
    
    // test
    console.log(nums.includes(7)); // true
    console.log(nums.includes(10)); // false
    console.log(nums.includes(7, 1)); // false
    

原因: 我們都知道在es6中存在多個(gè)類似功能的函數(shù)喧枷,比如:

findIndex(function)虹统、find(function)indexOf(value)

那么為什么還會(huì)有includes呢隧甚?

  • 首先车荔,改名風(fēng)波:

    Array.prototype.includes 的前身提案名是Array.prototype.contains ,但是沒有正式推出戚扳,于是很多網(wǎng)站自行hack了忧便。

    假如規(guī)范實(shí)現(xiàn)contains, 會(huì)出現(xiàn)contains 無法被for..in讀出來(因?yàn)閖s中所有原生提供的方法屬性都是不可枚舉的,只能通過屬性的屬性描述符獲取getOwnPropertyDescriptor(Array.prototype, 'indexOf'))帽借,而之前自行hack的contains的是可以被讀出來的珠增。

    會(huì)出現(xiàn)代碼沒變動(dòng),在新規(guī)范推出后產(chǎn)生bug的情況砍艾。因此初稿階段蒂教,考慮新規(guī)范會(huì)使得許多現(xiàn)有網(wǎng)站出問題,所以改名includes脆荷。

  • 其次凝垛,雖然我們用indexOf可以模擬includes的行為,但出于語義描述不清楚的原因蜓谋,所以要改梦皮。

    includes 表達(dá)了 是否包含該項(xiàng)的意思。

    indexOf 表達(dá)了查找數(shù)組中第一次出現(xiàn)對(duì)應(yīng)元素的索引是什么桃焕,在針對(duì)返回的索引進(jìn)一步處理的意思剑肯。

    has 為什么不叫has呢,因?yàn)閔as一般表示key中是否有(Map.prototype.has)观堂,includes表示value中是否有让网。

  • 那么他的判斷是否相等的方式是什么呢?答案是:SameValueZero 师痕,es6中有4種相等算法

    • 松散相等比較:實(shí)現(xiàn)接口 ==

    • 嚴(yán)格相等比較:實(shí)現(xiàn)接口===溃睹,使用Array.prototype.indexOfArray.prototype.lastIndexOfcase-matching

    • SameValue: 實(shí)現(xiàn)接口Object.is()

    • SameValueZero: 實(shí)現(xiàn)接口借用了MapSet的方法七兜。

      // 注意
      // SameValue 中 +0 和 -0 是false
      Object.is(-0, +0); // false
      // SameValueZero 中 +0 和 -0 是true 和Set的判斷很像不是
      const s = new Set();
      s.add(0);
      s.has(-0); // true
      

思考: 從探究整個(gè)提案的流程丸凭,可以看出一個(gè)新特性的出現(xiàn)需要考慮很多方面的問題。

類比之下,我們的項(xiàng)目在修改的時(shí)候 惜犀,也需要考慮是否會(huì)對(duì)其他的東西產(chǎn)生影響铛碑,以及當(dāng)前的方案是否最優(yōu)。

思考一下虽界,我們現(xiàn)在有用到查詢數(shù)組中是否包含某個(gè)元素的情況汽烦,我猜測(cè)大多數(shù)都是用的indexOf, 不過既然更優(yōu)的api,官方已經(jīng)提出來了 ,我們是否可以考慮換一下莉御,畢竟可以減少碼量撇吞,同時(shí)語義更加清晰不是。

let arr = [1, 2, 3];

if (arr.indexOf(1) > -1) {...}
// ==> 等價(jià)于
if (arr.includes(1)) {...}
  1. 語法變化:新的指數(shù)運(yùn)算符**

    規(guī)定: 雖然Math.pow() 是已經(jīng)支持了指數(shù)運(yùn)算的方法礁叔,但是正式的運(yùn)算符** 看起來會(huì)會(huì)讓開發(fā)者更容易閱讀和理解牍颈。** 的左邊是基數(shù),右邊是指數(shù)琅关。 如下:

    let result = 10 ** 2;
    
    console.log(result); // 100
    console.log(result === Math.pow(10, 2)) // true
    
    // 當(dāng)然 支持 **= 即 a = a**b <==> a **= b
    
    

原因: 沒錯(cuò) 煮岁,就是為了更容易書寫和閱讀。

思考: 官方都時(shí)刻關(guān)心涣易,可見容易書寫和閱讀多么的重要画机,我以為我們的代碼可以更加的簡(jiǎn)潔和易讀。推薦一個(gè)代碼規(guī)范地址:https://github.com/ryanmcdermott/clean-code-javascript

  1. 新的語法錯(cuò)誤

    規(guī)定:在參數(shù)被解構(gòu)或者有默認(rèn)參數(shù)的函數(shù)中新症,禁止使用嚴(yán)格模式"use strict"指令步氏。否則會(huì)拋出錯(cuò)誤

    // 正確
    function good(first, second) { return first}
    
    // 拋出錯(cuò)誤 原因:有默認(rèn)參數(shù)并且使用了"use strict"
    function notGood(first, second = first) {
        "use strict";
        return first;
    }
    
    // 拋出錯(cuò)誤 原因:參數(shù)被解構(gòu)并且使用了"use strict"
    function notGood2({first, second}) {
        "use strict";
        return first;
    }
    

原因:實(shí)現(xiàn)運(yùn)行在嚴(yán)格模式下的參數(shù)非常困難,比如:

function foo(first = this) {
 "use strict";
    return first
}

在嚴(yán)格模式下first被認(rèn)為是undefined徒爹,可是參數(shù)的默認(rèn)值也可以是函數(shù)(通過apply , call指定上下文的調(diào)用方式)荚醒,這就導(dǎo)致大多數(shù)的JavaScript引擎均不實(shí)現(xiàn)此功能,而是將其等同于全局對(duì)象瀑焦。

思考:當(dāng)我們遇到一個(gè)不好實(shí)現(xiàn)或者解決的問題的時(shí)候腌且,做個(gè)智者梗肝,未嘗不是一種明智的選擇(繞過它/拋異常)榛瓮。

Es8(es2017)

  1. Object、String的靜態(tài)方法
  2. 在函數(shù)參數(shù)列表中尾隨逗號(hào)并調(diào)用
  3. 異步功能巫击、共享內(nèi)存和原子

具體如下:

  1. Object禀晓、String的靜態(tài)方法

    規(guī)定: 擴(kuò)展了 Object和 String的功能

    • Object.values/Object.entries/Object.getOwnPropertyDescriptors()

      • Object.values接受一個(gè)對(duì)象并返回所有值構(gòu)成的數(shù)組,其順序和for … in 的順序相同坝锰。

      • Object.entries接受一個(gè)對(duì)象并返回?cái)?shù)組粹懒,每個(gè)元素都是一個(gè)包含兩個(gè)元素的數(shù)組。第一個(gè)是對(duì)象的key, 第二個(gè)是對(duì)象的value顷级, 其順序和for … in 的順序相同凫乖。

      • Object.getOwnPropertyDescriptors 獲取屬性描述符,即對(duì)象所有自己的屬性描述符。包括value/writable/enumerable/configurable

        let obj = {
            one: 'hh',
            second: 'dd',
            thrid: 'zz'
        }
        Object.values(obj); // ["hh", "dd", "zz"]
        Object.entries(obj); // [["one", "hh"], ["second", "dd"], ["thrid", "zz"]]
        Object.getOwnPropertyDescriptor(obj, 'one'); // {value: "one", writable: true, enumerable: true, configurable: true}
        
    • String padding 用另一個(gè)字符串填充填充當(dāng)前字符串帽芽,直到結(jié)果字符串達(dá)到給定的長(zhǎng)度為止删掀,第二個(gè)參數(shù)默認(rèn)為空格。

      • String.padStart(長(zhǎng)度, 填充字符串|' ') 從開頭填充, 填充字符從左往右填充

      • String.padEnd(長(zhǎng)度, 填充字符串|' ') 從末尾向后填充导街,填充字符從左往右填充

        'abc'.padStart(10); // "       abc" 
        'abc'.padStart(10, 'foo'); // "foofoofabc"
        'abc'.padStart(6, '1234565'); // "123abc"
        'abc'.padStart(8, '0'); // '00000abc'
        'abc'.padStart(1); // 'abc'
        
        'abc'.padEnd(10); // "abc       " 
        'abc'.padEnd(10, 'foo');// "abcfoofoof"
        'abc'.padEnd(6, '123456'); // 'abc123'
        'abc'.padEnd(1); //  'abc'
        

思考:

Object.valuesObject.keys 對(duì)應(yīng)使用披泪,

在對(duì)一些私密信息進(jìn)行處理的時(shí)候,需要將一些數(shù)字進(jìn)行加*隱藏搬瑰,之前的寫法可能是進(jìn)行遍歷數(shù)組逐個(gè)替換款票,現(xiàn)在有了padStart,可以這樣試一下:

// 對(duì)身份進(jìn)行隱藏顯示
const fullNumber = '320321197803069527';

// old
const hideLen = fullNumber.length - 4;
let maskedNumber = ''
for (let i = 0; i < fullNumber.length; i++) {
    if (i < hideLen) {
     maskedNumber += '*';
    }else {
        maskedNumber += fullNumber[i]
    }
}
console.log(maskedNumber); // **************9527

// new 
const last4Digits = fullNumber.slice(-4);
const maskedNumberNew = last4Digits.padStart(fullNumber.length, '*'); 
console.log(maskedNumberNew); // **************9527 很簡(jiǎn)潔泽论,思路很清晰不是

還有一種情形就是 給定字符串長(zhǎng)度艾少,超出的以省略號(hào)表示 (這里不考慮超出指定長(zhǎng)度省略號(hào)表示),試試看翼悴?

const str = 'Tom Jackson';
// 期望輸出: 'Tom...'
  1. 在函數(shù)參數(shù)列表中尾隨逗號(hào)并調(diào)用

    規(guī)定:在函數(shù)的參數(shù)列表中姆钉,最后一個(gè)參數(shù)以逗號(hào)結(jié)尾,如:

    function myFun(
     p1, 
        p2,
    ) {}
    myFun(
        'param1',
        'param2',
    )
    

    原因:

    1. 如果最后一項(xiàng)改變了位置抄瓦,則不必添加和刪除逗號(hào)潮瓶。
    2. 它可以幫助版本控制系統(tǒng)跟蹤實(shí)際更改的內(nèi)容。
  1. 異步功能

    規(guī)定: 異步功能钙姊,指的是定義一個(gè)異步函數(shù)毯辅,也就是一個(gè)返回異步對(duì)象的函數(shù),返回Promise或者函數(shù)上加async標(biāo)記煞额。

原因:當(dāng)異步功能有多個(gè)的時(shí)候思恐,在一個(gè)函數(shù)中就會(huì)難以維護(hù),違背了單一職責(zé)原則膊毁, 就需要拆分出不同的方法胀莹,因此就有了異步功能。

思考: 異步功能很好的將業(yè)務(wù)封裝在了功能函數(shù)之中婚温,調(diào)用者只需要關(guān)心成功和失敗兩種狀態(tài)(resolve和reject)描焰,這樣會(huì)使得代碼更具有可讀性。

這種場(chǎng)景目前用的最多的是在接口函數(shù)的編寫中栅螟,它讓我們不用太過關(guān)心接口的發(fā)送以及對(duì)返回?cái)?shù)據(jù)的處理荆秦,只需要使用即可。

  1. 共享內(nèi)存和原子

    規(guī)定: 引入新的構(gòu)造函數(shù) SharedArrayBuffer 和 具有輔助函數(shù)的命名空間對(duì)象 Atomics力图, 用原子操作進(jìn)行通信的程序步绸,即使在并行CPU上也能確保定義良好的執(zhí)行順序。全局變量 Atomics吃媒,它的方法具有三個(gè)主要用例瓤介。

    • 同步化
    • 等待通知
    • 原子操作
    Atomics.store() // 寫入
    Atomics.load() // 讀取
    Atomics.wait() // 等待
    Atomics.wake() // 喚醒
    

    原因: 雖然用到的地方很少吕喘,但是作為一門語言,對(duì)于并行操作還是要支持的刑桑。Web workers 將任務(wù)并行引入了 JavaScript 兽泄。還記得PWA嗎?它的核心就在與本地開啟了一個(gè)service worker漾月,并對(duì)數(shù)據(jù)進(jìn)行了緩存以及代理病梢。

    思考: 要實(shí)現(xiàn)并行,需要滿足兩點(diǎn):一個(gè)是數(shù)據(jù)的并行梁肿,一個(gè)是代碼的并行蜓陌。這里SharedArrayBuffer作為共享陣列緩沖區(qū)是更高抽象的基本構(gòu)建塊。 它允許多個(gè)workers和主線程之間共享SharedArrayBuffer對(duì)象的字節(jié)吩蔑。同時(shí)Atomics的 方法可以用來與其他 workers 進(jìn)行同步钮热。

    詳情可以了解https://www.html.cn/archives/7724

Es9(es2018)

  1. 解除模板字面量限制
  2. 正則表達(dá)式相關(guān)
  3. 對(duì)象解構(gòu)中的rest操作符(...)/對(duì)象字面量中的spread操作符(...)
  4. Promise.prototype.finally 和 異步的迭代

具體如下:

  1. 解除模版字面量的限制

    規(guī)定: 對(duì)于模版字面量中,如果存在非法轉(zhuǎn)義字符 烛芬,則將模版字面量設(shè)置為undefined隧期。不過可以通過.raw訪問原始值。

    function tag(strs) {
        console.log(strs[0] === undefined); 
        console.log(strs.raw[0] === '\\unicode and \\u{55}')
    }
    tag`\unicode and \u{55}`; // true true
    
    const badSequence = `bad escape sequence: \unicode`; // Uncaught SyntaxError: Invalid Unicode escape sequence
    

    原因:解決模版字面量中存在非法轉(zhuǎn)義字符報(bào)錯(cuò)的問題赘娄。

    思考:在處理字符串的時(shí)候仆潮,我們多是需要注意處理需要進(jìn)行轉(zhuǎn)義的字符,此時(shí)有了這個(gè)特性 遣臼,使的我們可以封裝個(gè)公共的方法性置,放心的使用模版字面量,沒必要進(jìn)行而外的處理了揍堰。

  1. 正則表達(dá)式相關(guān)

    • . 的使用

      規(guī)定: es9支持了/s模式下鹏浅,. 可以匹配換行符。

      console.log(/./s.test("\n")); //  true
      console.log(/./s.test("\r")); //  true
      

      原因:正則中.看似可以匹配任何字符屏歹,但換行符除外隐砸,當(dāng)時(shí)大家用[\w\W]替代了.。這個(gè)終究是個(gè)缺陷蝙眶。于是增加了在 /s 模式下季希,. => [\w\W]

  • 對(duì)捕獲組進(jìn)行命名:

    規(guī)定: 使用捕獲組需要通過指定捕獲組名稱來進(jìn)行引用械馆,每個(gè)名稱是唯一的胖眷,避免沖突武通。語法:?<name>

    const regExp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
    const result = regExp.exec('2020-10-21');
    console.log(result.groups.year === '2020'); //true => result[1] === '2020'
    console.log(result.groups.month === '10'); //true => result[2] === '10'
    console.log(result.groups.day === '21');//true => result[3] === '21'
    // 其中 result[0] === '2020-10-21' 
    
    // 命名捕獲組這塊 建議結(jié)合解構(gòu)字面量一起使用 會(huì)更加清晰
    const { groups: { year, month, day } } = regExp.exec('2020-10-21');
    

    原因:對(duì)捕獲組命名可以讓調(diào)用更加清晰霹崎。

  • 支持了后行斷言:

    規(guī)定: es9之前只支持先行斷言,現(xiàn)在支持了后行斷言冶忱。

    正向后行斷言:(?<=...) 表示之前的字符串能匹配

    const re = /(?<=\d{3}) meters/; // 表示 meters 之前 匹配三個(gè)數(shù)字
    console.log(re.test('10 meters')); // false
    console.log(re.test('100 meters')); // true
    

    負(fù)向后行斷言:(?<!...) 表示之前的字符串不能匹配

    const re = /(?<!\d{3}) meters/; // 表示 meters 之前 不能匹配三個(gè)數(shù)字
    console.log(re.test('10 meters')); // true
    console.log(re.test('100 meters')); // false
    

    原因: 彌補(bǔ)之前只能支持先行斷言的缺陷尾菇。

    思考: 正則中完整的斷言定義:正/負(fù)向斷言 與 先/后行斷言 的笛卡爾積組合(互相組合得到4種結(jié)果)。

    補(bǔ)充一下正向先行斷言負(fù)向先行斷言

    // 正向先行斷言
    const re = /meters(?= 10)/;
    console.log(re.test('meters 10')); // true
    console.log(re.test('meters 5')); // false
    
    // 負(fù)向先行斷言
    const re2 = /meters(?! 10)/; 
    console.log(re.test('meters 10')); // false
    console.log(re.test('meters 5')); // true
    
  • Unicode 屬性轉(zhuǎn)義

    規(guī)定:正則支持了更加強(qiáng)大的unicode匹配方式疟羹。在/u(修飾符u指unicode)模式下温赔,通過\p{}大括號(hào)內(nèi)提及unicode字符屬性來匹配字符肠仪。

    可以用\p{Number}匹配所有數(shù)字

    可以用\p{Alphabetic}匹配所有Alphabetic元素衰絮,包括漢字惭载,字母等

    可以用\p{White_Space}匹配空格泳猬、制表符制轰、換行符灯谣。

    等等缆八。

    const regex = /^\p{Number}+$/u;
    regex.test("231???"); // true
    regex.test("???"); // true
    regex.test("ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ"); // true
    
    const str = "漢";
    console.log(/\p{Alphabetic}/u.test(str)); //  true
    // the \w shorthand cannot match 漢
    console.log(/\w/u.test(str)); // false
    
    /^\p{White_Space}+$/u.test('\n \r \t'); // true
    

    原因: 創(chuàng)建支持unicode的正則表達(dá)式不再麻煩曲掰,更加易讀。使用Unicode屬性轉(zhuǎn)義符的代碼將保持“最新”狀態(tài):每當(dāng)Unicode標(biāo)準(zhǔn)得到更新時(shí)奈辰,ECMAScript引擎就會(huì)更新其數(shù)據(jù)栏妖。

  1. 對(duì)象解構(gòu)中的rest操作符(...)/對(duì)象字面量中的spread操作符(...)

    // 對(duì)象解構(gòu)中的rest操作符(...)
    const {one, two, ...others} = { one: 'one', two: 'two', three: 'three', four: 'four'};
    console.log(others); // { three: 'three', four: 'four' }
     
    // 對(duì)象字面量中的spread操作符(...)
    const nums = {one, two, ...others};
    console.log(nums);// { one: 'one', two: 'two', three: 'three', four: 'four'};
    

    **思考: **需要注意的是 在使用對(duì)象字面量的時(shí)候 如果有key重復(fù),那么對(duì)象中后面的key的值會(huì)覆蓋前面的奖恰。

  2. Promise.prototype.finally 和 異步的迭代

    • Promise.prototype.finally

      規(guī)定:一旦執(zhí)行了Promise的resolve回調(diào)或者reject回調(diào)吊趾,最終都會(huì)執(zhí)行finally回調(diào)

      思考:總有一些相同的處理需要在resolve回調(diào)或者reject回調(diào)后處理,比如:資源的回收或者網(wǎng)絡(luò)請(qǐng)求時(shí)loading的狀態(tài)修改等瑟啃。 平時(shí)我們會(huì)在resolve回調(diào)或者reject回調(diào)中都添加或者提取一個(gè)公共方法÷鄯海現(xiàn)在會(huì)讓我們更省力和美觀。

    • 異步的迭代

      規(guī)定:這個(gè)是for...of的一種變體蛹屿,他允許在由異步組成的可迭代對(duì)象上進(jìn)行迭代孵奶。

      async function asyncFun() {
          const promises = [
              fetch('f1.json'),
             fetch('f2.json'),
              fetch('f3.json'),
          ];
          // 正常的迭代
          for (const promiseItem of promises) {
              console.log(item); // =>  輸出 promise
         }
          
          // 正常的迭代
          for await (const promiseItem of promises) {
              console.log(item); // =>  輸出 resolved response
         }
      }
      

      思考: 適合的場(chǎng)景會(huì)是 多個(gè)異步同步執(zhí)行,并對(duì)每個(gè)結(jié)果有統(tǒng)一的處理方式蜡峰。比如:對(duì)文件的處理了袁。

Es10(es2019)

  1. Array.prototype.flat 和 Array.prototype.flatMap

  2. Object.fromEntries

  3. String.prototype.trimStart, String.prototype.trimEnd

  4. Symbol的描述訪問器

  5. try { } catch {} 可省略catch參數(shù)的寫法

  6. 對(duì)行分隔符\u2028和段落分隔符\u2029的支持,

  7. JSON.stringify對(duì)特殊字符的轉(zhuǎn)義處理

  8. Array.prototype.sort

  9. Function.prototype.toString

具體如下:

  1. Array.prototype.flat 和 Array.prototype.flatMap

    規(guī)定:

    Array.prototype.flat(Number) 湿颅,降緯度數(shù)組载绿,具體下降多少維度視參數(shù)而定,知道無法繼續(xù)降維為止油航。默認(rèn)為1

    Array.prototype.flatMap(Function) 崭庸,flat和map功能的組合,接受一個(gè)函數(shù), 返回一個(gè)處理后的降維了1個(gè)的數(shù)組谊囚。

    const fruits = [['apple', 'banana'], ['蘋果', '香蕉']];
    console.log(fruits.flat()); // ['apple', 'banana', '蘋果', '香蕉']
    
    const fruits2 = [['apple'], ['banana'], ['蘋果'], ['香蕉']];
    const mappedAndFlatten = fruits2.flatMap((fruit, index) => [fruit + '_fruit']);
    console.log(mappedAndFlatten); // ["apple_fruit", "banana_fruit", "蘋果_fruit", "香蕉_fruit"]
    

    思考:

    對(duì)比我們平常使用的解構(gòu)方法, 需要遞歸遍歷:

    function reduceDimension(arr){
        let ret = [];
        let targetArr = function(arr){
            arr.forEach(function(item){
                item instanceof Array ? targetArr(item) : ret.push(item);
            });
        }
        targetArr(arr);
        return ret;
    }
    
    // 等同于 arr.flat(Infinity)
    

    發(fā)現(xiàn) flat(Infinity) 無疑更簡(jiǎn)潔(Infinity 作為數(shù)值中的無限大怕享,可以保證數(shù)組能夠完全解構(gòu))。

  1. Object.fromEntries

    規(guī)定: 將 由鍵值對(duì)組成的數(shù)組轉(zhuǎn)換成一個(gè)對(duì)象, 與 Object.entries功能相反镰踏。

    const fruits = { apple: '蘋果', banana: '香蕉', orange: '橘子'};
    const entries = Object.entries(fruits);// [["apple", "蘋果"],["banana", "香蕉"] ,["orange", "橘子"]]
    const fromEntries = Object.fromEntries(entries); // { apple: '蘋果', banana: '香蕉', orange: '橘子'}
    

    思考: 這是針對(duì)這種特定數(shù)據(jù)結(jié)構(gòu)的格式化 函數(shù)函筋。對(duì)于一個(gè)對(duì)象如果需要同時(shí)修改對(duì)象的key-value, 直接修改不方便,我們可以先將一個(gè)對(duì)象通過Object.entries轉(zhuǎn)換成數(shù)組奠伪,進(jìn)行修改跌帐,完成后通過Object.fromEntries轉(zhuǎn)換回來首懈。

  1. String.prototype.trimStart, String.prototype.trimEnd

    • trimStart :去除字符串前面的空格

    • trimEnd: 去除字符串后面的空格

  1. Symbol的描述訪問器

    規(guī)定: 通過 Symbol.prototype.description可以獲取定義Symbol時(shí)的具體數(shù)值

    const OPEN = Symbol('STATUS_OPEN');
    // old 可以通過 toString() 來獲取描述信息
    console.log(OPEN.toString()); // "Symbol('STATUS_OPEN')"
    
    // new 通過 description屬性獲取
    console.log(OPEN.description); // "STATUS_OPEN"
    

    思考: Symbol的出現(xiàn) 讓我們?cè)诔A康氖褂弥写罅渴褂茫贿^有時(shí)侯需要獲取它的描述值來做一些判斷谨敛。

    const BANNER = {
        LEFT: Symbol('left'),
        RIGHT: Symbol('right'),
    }
    
    // 使用時(shí)候
    if (BANNER.LEFT.description === 'left') {
        // do something
    }
    
  1. try { } catch {} 可省略catch參數(shù)的寫法

    規(guī)定: catch后面的括號(hào)以及參數(shù)在不用的時(shí)候可以省略

    try { } catch(err) {}
    try { } catch {}  // 不會(huì)報(bào)錯(cuò)
    

    思考:有些時(shí)候我們不需要對(duì)catch 的err 數(shù)據(jù)進(jìn)行操作究履,這個(gè)時(shí)候如果傳遞了,但是未使用脸狸,那么eslint 可能會(huì)警告我們代碼中存在可優(yōu)化最仑。本著不用不寫的原則,省略無疑是很好的一種方式炊甲。

  1. 對(duì)行分隔符\u2028和段落分隔符\u2029的支持

    規(guī)定: es10之前 '\u2028''\u2020'這種寫法會(huì)報(bào)錯(cuò)盯仪,現(xiàn)在不會(huì)啦。

  1. JSON.stringify對(duì)特殊字符的轉(zhuǎn)義處理

    規(guī)定: JSON.stringify 在處理\uD800\DFFF之間的字符蜜葱,如果找不到對(duì)應(yīng)的全景,直接返回轉(zhuǎn)義后的字符。

    JSON.stringify('\uDF06\uD834'); // '"\\udf06\\ud834"'
    
  1. Array.prototype.sort

    規(guī)定: es10之前 V8對(duì)于包含10個(gè)以上的數(shù)組排序時(shí)采用了不穩(wěn)定的快速排序算法牵囤,這個(gè)算法可能會(huì)改變?cè)瓉頂?shù)組里面相同數(shù)值的元素的先后關(guān)系爸黄。 通過采用原地排序保證數(shù)組中相同數(shù)值元素的先后關(guān)系。避免了順序被改變的問題揭鳞。

  1. Function.prototype.toString

    規(guī)定:返回一個(gè)表示函數(shù)源代碼的字符串炕贵,包括格式和注釋,比較精確野崇。

    function add(num1, num2) {
        /* add */
        return num1 + num2;
    }
    
    add.toString(); 
    // "function add(num1, num2) {
    //    /* add */
    //    return num1 + num2;
    // }" 
    

Es11(es2020)

  1. String.prototype.matchAll

  2. Promise.allSettled

  3. export * as ns from 'module'

  4. for-in 對(duì)于迭代對(duì)象順序的統(tǒng)一

  5. 鏈合并運(yùn)算符 ?. 以及 Null判斷運(yùn)算符 ??

  6. 新增原始類型 BigInt 称开,可以表示任意精度的整數(shù)

  7. import 動(dòng)態(tài)導(dǎo)入

  8. import.meta

  9. 標(biāo)準(zhǔn)化的全局對(duì)象

具體如下:

  1. String.prototype.matchAll

    規(guī)定: 返回所有與正則表達(dá)式相匹配字符串的結(jié)果的迭代器,包括捕獲組乓梨。相比于match, 它提供的信息更全鳖轰。

    const regexp = /t(e)(st(\d?))/g;
    const str = 'test1test2';
    
    // 曾經(jīng) 我們通過 while 和 exec配合來獲取比較全的匹配信息
    let result = null;
    while((result = regexp.exec(str)) !== null) {
     console.log(result);
    }
    // >  ["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined]   
    // >  ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined]
    
    // 現(xiàn)在 我們用matchAll 就好了
    const array = [...str.matchAll(regexp)];
    for (result of array) {
        console.log(result);
    }
    // >  ["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined]   
    // >  ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined]
    
  1. Promise.allSettled

    規(guī)定:對(duì)比Promise.all 方法,Promise.allSettled 當(dāng)每個(gè)Promise 無論失敗還是成功都會(huì)走回調(diào)函數(shù)扶镀。

    const promiseArr = [
        Promise.resolve(100),
        Promise.reject(null),
        Promise.reject(new Error('Oh No')),
    ]
    
    Promise.all(promiseArr).then(results => {
        // 不會(huì)執(zhí)行
        console.log('All Promise Settled', results);
    });
    
    Promise.allSettled(promiseArr).then(results => {
        console.log('All Promise Settled', results);
    });
    // [{status: "fulfilled", value: 100},
    // {status: "rejected", reason: null},
    // {status: "rejected", reason: Error: Oh No at <anonymous>:4:20}]
    

    思考:當(dāng)我們?cè)谶M(jìn)行多個(gè)接口請(qǐng)求的時(shí)候蕴侣,如果通過Promise.all ,不能保證回調(diào)一定會(huì)執(zhí)行臭觉,這時(shí)候如果有l(wèi)oading狀態(tài)的昆雀,無疑會(huì)出現(xiàn)問題,無法在回調(diào)中更新蝠筑。如果我們并不關(guān)心接口是否調(diào)用成功狞膘,這個(gè)時(shí)候Promise.allSettled 無疑是更合適的。

  1. export * as ns from 'module'

    規(guī)定: 在一個(gè)文件中引用另外一個(gè)文件并導(dǎo)出他的一種縮寫什乙。

    export * as utils from './utils.mjs'
    
    // 等價(jià)于 ==> 
    import * as utils from './utils.mjs'
    export { utils }
    

    思考: 在react中使用組件的時(shí)候挽封,我們會(huì)對(duì)一個(gè)目錄下的多個(gè)文件 通過index.js導(dǎo)出。好處在于當(dāng)前文件中并不會(huì)真的導(dǎo)入文件對(duì)象的引用稳强,比如以上的utils為undefined场仲。

    // index.js old
    import * as Header from './header.jsx'
    import * as Footer from './footer.jsx'
    // ...
    export { Header }
    export { Footer }
    // ...
    
    // index.js new 
    export * as Header from './header.jsx';
    export * as Footer from './footer.jsx';
    export * as Body from './body.jsx';
    export * as Nav from './nav.jsx';
    
  1. for-in 對(duì)于迭代對(duì)象順序的統(tǒng)一

    規(guī)定:雖然瀏覽器自己保持了 for in的順序和悦,但是在es11中進(jìn)行了標(biāo)準(zhǔn)化退疫。

  1. 鏈合并運(yùn)算符 ?. 以及 Null判斷運(yùn)算符 ??

    規(guī)定:鏈合并運(yùn)算符 避免了調(diào)用時(shí)左側(cè)的對(duì)象是否為null或undefined的判斷渠缕,Null判斷運(yùn)算符 為屬性值為null或undefined時(shí),指定默認(rèn)值

    const userName = (list && list.info 
                      && list.info.base 
                      && list.info.base.userName
                     ) || 'userName';
    // => 等價(jià)于
    const userName = list?.info?.base?.userName ?? 'userName';
    

    思考: ?? 類似于 || 褒繁,區(qū)別在于:

    • ?? 只當(dāng)左側(cè)為 null/undefined的時(shí)候才會(huì)指定右側(cè)默認(rèn)值

    • || 當(dāng)左側(cè)所有轉(zhuǎn)換后boolean值為false 的時(shí)候會(huì)指定右側(cè)默認(rèn)值(包括 0 )

      在某些情況下 我們并不需要這種結(jié)果亦鳞,因此結(jié)合業(yè)務(wù)考慮使用哪一種。

  1. 新增原始類型 BigInt 棒坏,可以表示任意精度的整數(shù)

    規(guī)定: 顧名思義燕差,就是用來存放Number放不下的數(shù)字

    let maxNum = 9007199254740992; // Number的最大值 pow(2, 53) - 1
    console.log(maxNum + 1); // 9007199254740992
    
    maxNum = 9007199254740992n;
    console.log(maxNum + 1n); // 9007199254740993n
    console.log(typeof maxNum === 'bigint'); // true
    console.log(maxNum + 1); // Uncaught TypeError: Cannot mix BigInt and other types 
    

思考: 在進(jìn)行大數(shù)計(jì)算的時(shí)候,之前需要通過豎式運(yùn)算坝冕,一種從個(gè)位往前一個(gè)一個(gè)相加求和的方式徒探,比較麻煩。現(xiàn)在直接用BigInt就可以了

  1. import 動(dòng)態(tài)導(dǎo)入

    規(guī)定: 返回所請(qǐng)求模塊的模塊名稱空間對(duì)象的Promise喂窟,所以也可以使用async/await

    const modulePath = './file.js';
    import(modulePath)
     .then((module) => {
         // do something
     });
    // or
    (async function() {
        const modulePath = './file.js';
        const module = await import(modulePath);
        // do somthing
    })();
    

    思考:import 的動(dòng)態(tài)導(dǎo)入支持 一方面可以讓我們按需加載测暗,另一方面的可能會(huì)出現(xiàn)濫用的可能,對(duì)靜態(tài)文件分析造成一定程度上的阻礙(比如:tree-shaking 就是依賴于 import的靜態(tài)導(dǎo)入磨澡,如果都做成了動(dòng)態(tài)導(dǎo)入碗啄,那么該功能的能力會(huì)收到很大的影響)。

  1. import.meta

    規(guī)定: 可以通過import.meta獲取module的信息

    <script type="module" src="module.js"></script>
    
    // module.js
    console.log(import.meta) // 得到一個(gè)對(duì)象 包含模塊的信息{ url: "file:///home/user/module.js" }
    

    思考:在使用一個(gè)模塊時(shí)稳摄,有時(shí)需要知道模板本身的一些信息(比如模塊的路徑)稚字。這是import.meta的用處。

  1. 標(biāo)準(zhǔn)化的全局對(duì)象

    規(guī)定:全局變量之前在各個(gè)平臺(tái)未統(tǒng)一厦酬,需要自行標(biāo)準(zhǔn)化胆描。

    var getGlobal = function () {
        if (typeof self !== 'undefined') { return self; }
        if (typeof window !== 'undefined') { return window; }
        if (typeof global !== 'undefined') { return global; }
        throw new Error('unable to locate global object');
    }
    
    // getGlobal() 等同于 globalThis
    

其他可能的提案

  1. do表達(dá)式

  2. 雙冒號(hào)運(yùn)算符

  3. 管道運(yùn)算符

  4. #!命令

具體如下:

  1. do表達(dá)式

    規(guī)定: 通過在塊級(jí)作用域前添加do , 讓塊級(jí)作用域可以變?yōu)楸磉_(dá)式仗阅。也就是說可以返回值袄友。do 也提供了單獨(dú)的作用域。do表達(dá)式的邏輯:封裝什么就會(huì)返回什么

    let x = do {
      let t = f();
      t * t + 1;
    };
    // x的值等于 t*t+1的結(jié)果
    
    // 等同于 <表達(dá)式>
    do { <表達(dá)式>; }
    // 等同于 <語句>
    do { <語句> }
    

    思考:我們?cè)趯慾sx的時(shí)候霹菊,do很好用剧蚣。以下避免了三元運(yùn)算符的使用,同時(shí)代碼意圖比較清晰旋廷。

    return (
      <nav>
        <Home />
        {
          do {
            if (loggedIn) {
              <LogoutButton />
            } else {
              <LoginButton />
            }
          }
        }
    
      </nav>
    )
    
  1. 雙冒號(hào)運(yùn)算符

    規(guī)定:即“函數(shù)綁定”(function bind)運(yùn)算符鸠按,用來取代callapply饶碘、bind調(diào)用目尖。左邊是一個(gè)對(duì)象,右邊是一個(gè)函數(shù)

    foo::bar;
    // 等同于
    bar.bind(foo);
    
    foo::bar(...arguments);
    // 等同于
    bar.apply(foo, arguments)    
    
  2. 管道運(yùn)算符

    規(guī)定:JavaScript 的管道是一個(gè)運(yùn)算符扎运,寫作|>瑟曲。它的左邊是一個(gè)表達(dá)式饮戳,右邊是一個(gè)函數(shù)。支持await洞拨。

    x |> f
    // 等同于
    f(x)
    
    x |> await f
    // 等同于
    await f(x)
    

    思考:管道運(yùn)算符最大的好處扯罐,就是可以把嵌套的函數(shù),寫成從左到右的鏈?zhǔn)奖磉_(dá)式烦衣。

    function doubleSay (str) {
      return str + ", " + str;
    }
    function capitalize (str) {
      return str[0].toUpperCase() + str.substring(1);
    }
    function exclaim (str) {
      return str + '!';
    }
    
    let msg = 'hello';
    const result = msg |> doubleSay |> capitalize |> exclaim;
    // 等同于
    const resultNew = exclaim(capitalize(doubleSay(msg)));
    
  1. #!命令

    規(guī)定: JavaScript 腳本引入了#!命令歹河,寫在腳本文件或者模塊文件的第一行。Unix 命令行就可以直接執(zhí)行腳本花吟。同時(shí)對(duì)于JavaScript 引擎來說秸歧,會(huì)把#!理解成注釋,忽略掉這一行衅澈。

    // 寫在腳本文件第一行 hello.js
    #!/usr/bin/env node
    'use strict';
    console.log(1);
    
    # 以前執(zhí)行腳本的方式
    $ node hello.js
    # 現(xiàn)在執(zhí)行 的方式
    $ ./hello.js
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末键菱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子今布,更是在濱河造成了極大的恐慌经备,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件险耀,死亡現(xiàn)場(chǎng)離奇詭異弄喘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)甩牺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門蘑志,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贬派,你說我怎么就攤上這事急但。” “怎么了搞乏?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵波桩,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我请敦,道長(zhǎng)镐躲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任侍筛,我火速辦了婚禮萤皂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匣椰。我一直安慰自己裆熙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著入录,像睡著了一般蛤奥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上僚稿,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天凡桥,我揣著相機(jī)與錄音,去河邊找鬼贫奠。 笑死唬血,一個(gè)胖子當(dāng)著我的面吹牛望蜡,可吹牛的內(nèi)容都是我干的唤崭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼脖律,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谢肾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起小泉,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤芦疏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后微姊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酸茴,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年兢交,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薪捍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡配喳,死狀恐怖酪穿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晴裹,我是刑警寧澤被济,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站涧团,受9級(jí)特大地震影響只磷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泌绣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一钮追、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赞别,春花似錦畏陕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽犹芹。三九已至,卻和暖如春鞠绰,著一層夾襖步出監(jiān)牢的瞬間腰埂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工蜈膨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屿笼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓翁巍,卻偏偏與公主長(zhǎng)得像驴一,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子灶壶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345