ECMAScript 2020新增特性

前言

TC39 委員會于近期批準(zhǔn)了 ECMAScript 2020(即 ES2020)候選提案,即經(jīng)審定最終添加到 JavaScript 語言中的特性集。ES2020 候選提案是今年六月提交 ECMA 大會(General Assembly)的審批匯總儒将。


1. Promise.allSettled

Promise.all 缺陷

都知道 Promise.all 具有并發(fā)執(zhí)行異步任務(wù)的能力竹椒。

先復(fù)習(xí)一下Promise.all 的用法

let p1 = Promise.resolve({
    code: 200,
    list: ["數(shù)據(jù)1"]
})
let p2 = Promise.resolve({
    code: 200,
    list: ["數(shù)據(jù)2"]
})
let p3 = Promise.resolve({
    code: 200,
    list: ["數(shù)據(jù)3"]
})
?
Promise.all([p1,p2,p3]).then((result) => {
    // all方法并發(fā)的三個promise都是成功狀態(tài)會執(zhí)行
    console.log(result);
    /*
        返回的結(jié)果: [{…}, {…}, {…}]
    */
}).catch((error) => {
    console.log(error);
})
?

但時Promise.all 方法最大問題就是如果其中某個任務(wù)出現(xiàn)異常(reject)辜羊,所有任務(wù)都會掛掉,Promise直接進(jìn)入 reject 狀態(tài)。

let p1 = Promise.resolve({
      code: 200,
      list: ["數(shù)據(jù)2"]
  })
  let p2 = Promise.reject({
      code: 500,
      errorMsg:"服務(wù)器錯誤"
  })
?
  let p3 = Promise.resolve({
      code: 200,
      list: ["數(shù)據(jù)3"]
  })
?
  Promise.all([p1,p2,p3]).then((result) => {
     // 如果有一個promise 是reject,則不會執(zhí)行這個回調(diào)函數(shù)
      console.log(result);   
  }).catch((error) => {
      console.log(error);
      // 因?yàn)閜2 是reject 所以會執(zhí)行這個回到函數(shù)
      // {code: 500,errorMsg:"服務(wù)器錯誤"}
  })

如果小伙伴們在測試代碼的時候,記得重新打開頁面,不要刷新.

想象這個場景:在你的項(xiàng)目中,使用 Promise.all 來并發(fā)三個接口,每個接口都單獨(dú)對應(yīng)一個接口,請求數(shù)據(jù), 如果其中任意一個接口服務(wù)異常鳞尔,狀態(tài)是reject,這會導(dǎo)致三個區(qū)域數(shù)據(jù)全都無法渲染出來,因?yàn)槿魏?reject 都會進(jìn)入catch回調(diào), 很明顯早直,這是無法接受的.

Promise 在 ES2020 中新增了 Promise.allSettled() 寥假,就能好的 幫我們解決這個問題,Promise.allSetted 方法,無論一個任務(wù)是正常或是異常,都會返回對應(yīng)的狀態(tài)(fulfilled或者rejected)與結(jié)果(value),

let p1 = Promise.resolve({
    code: 200,
    list: ["數(shù)據(jù)2"]
})
let p2 = Promise.reject({
    code: 500,
    errorMsg:"服務(wù)器錯誤"
})
?
let p3 = Promise.resolve({
    code: 200,
    list: ["數(shù)據(jù)3"]
})
?
Promise.allSettled([p1,p2,p3]).then((result) => {
            // Promise.allSettled會在這里中處理并發(fā)promise狀態(tài)和結(jié)果
    console.log(result);
    /**
                返回的結(jié)果:
               [
                 {status: "fulfilled", value: {…}}
                 {status: "rejected", reason: {…}}
                 {status: "fulfilled", value: {…}}
               ]
            */
?
})

這樣我們在then方法中得到所有結(jié)果以后,我們就可以使用fill來過濾狀態(tài)為rejected掉的數(shù)據(jù)

2. String.prototype.matchAll


String.prototype上的match()方法僅返回完全匹配霞扬,但是沒有返回關(guān)于特定正則組的任意信息糕韧。String.prototype.matchAll可以返回比match()多很多的信息拾给。返回的迭代器除了精確匹配外還給了我們訪問所有的正則匹配捕獲組。

還節(jié)的match方法嗎?看下面一段代碼

let str = "<div>this is div</div><p>this is JS</p>";
let reg = /<\w+>(.*?)<\/\w+>/g;
console.log(str.match(reg));
/**
  返回結(jié)果:
     ["<div>this is div</div>", "<p>this is JS</p>"]
*/

我們都知道兔沃,match是可以正常匹配到所有匹配項(xiàng)蒋得,但卻沒辦法匹配到子項(xiàng)(group)。如果想要匹配子項(xiàng)乒疏,那么需要把全局匹配 /g 標(biāo)識去掉额衙。

let str = "<div>this is div</div><p>this is JS</p>";
let reg = /<\w+>(.*?)<\/\w+>/;
console.log(str.match(reg));
/**
 [
    0: "<div>this is div</div>"
    1: "this is div"
    groups: undefined
    index: 0
    input: "<div>this is div</div><p>this is JS</p>"
    length: 2
  ]
**/  

這樣可以獲取到匹配的父項(xiàng),包括子項(xiàng)(group)怕吴,但只能獲取到第一個滿足的匹配字符窍侧。

如果既想要匹配所有匹配項(xiàng),又想要匹配子項(xiàng)转绷,那么 match() 是無法滿足的伟件。ES2020 提供了 matchAll() 方法.

注意matchAll方法返回的是迭代器,因此我們需要遍歷獲取結(jié)果

let str = '<div>this is div</div><p>this is JS</p>';
let reg = /<\w+>(.*?)<\/\w+>/g;
let allMatchs = str.matchAll(reg);
?
for(let match of allMatchs){
    console.log(match)
}
/**
  第一次遍歷的結(jié)果:
    [
      0: "<div>this is div</div>"
      1: "this is div"
      groups: undefined
      index: 0
      input: "<div>this is div</div><p>this is JS</p>"
      length: 2
    ]
  第二次遍歷的結(jié)果:
    [
      0: "<p>this is JS</p>"
      1: "this is JS"
      groups: undefined
      index: 22
      input: "<div>this is div</div><p>this is JS</p>"
      length: 2
    ]
**/


3. import()


目前前端項(xiàng)目打包的資源越來越大,但應(yīng)用初始化時資源并不需要全量加載议经,為了提高頁面性能斧账,往往需要按需加載資源。Domenic Denicola提案的動態(tài)導(dǎo)入可以實(shí)現(xiàn)按需加載煞肾。這個類似函數(shù)的格式(不是繼承自Function .prototype)返回一個很強(qiáng)大的promise咧织。使用場景比如: 按需導(dǎo)入,在一個腳本中計(jì)算模塊名并加載執(zhí)行變得可能籍救。

element.onclick = () =>{
   import("/js/helpers.js")
    .then((module) =>{
        console.log(module)
    })
    .chatch((err) => {
        // load err
        console.log(err)
    })
}

因此我們也可以使用async異步函數(shù)來配置處理

element.onclick = async () =>{
   let module = await import("/js/helpers.js")
   // 處理 導(dǎo)入module模塊
}


4. BigInt


JavaScript 中 Number 類型都保存為 64 位浮點(diǎn)數(shù)习绢,精確度只能到 53 位,也就是說Js 中 Number類型只能安全的表示-(2^53-1)至 2^53-1 范的值,超出這個范圍的整數(shù)計(jì)算或者表示會丟失精度蝙昙。

console.log(Math.pow(2, 53));   // 9007199254740992
console.log(Math.pow(2, 53) + 1);  // 9007199254740992
console.log(Math.pow(2, 53) === Math.pow(2, 53) + 1); // true

且無法正確表示大于或等于 2^1024 的數(shù)值闪萄。

console.log(Math.pow(2, 1023));  // 8.98846567431158e+307
console.log(Math.pow(2, 1024));  // Infinity

ES2020 中引入了新的數(shù)據(jù)類型 BigInt, 讓Number.MAXSAFEINTEGER不再是JavaScript中的一個限制。BigInt是一個能表示任意精度整數(shù)的新基礎(chǔ)類型奇颠。你可以通過使用BigInt方法或者在一個數(shù)字后添加n后綴來把一個數(shù)字轉(zhuǎn)換為一個新的bigint類型败去。

// 使用BigInt
// 1. 字面量方式在數(shù)字字面量后面加n
let num = 123n;
console.log(num);   // 123n
console.log(typeof num); // bigint
?
// 2. 函數(shù)執(zhí)行的方式
let number = BigInt(Math.pow(2, 53) + 1);
console.log(number);  // 9007199254740992n
console.log(typeof number); // bigint

那么我們看看BigInt處理大型數(shù)字相加處理

let number = BigInt(Math.pow(2, 53));
letnumber2 = BigInt(Math.pow(2, 53));
console.log(number);  // 9007199254740992n
console.log(number2); // 9007199254740992n
?
letnum = number + number2;
console.log(num);      // 18014398509481984n
console.log(num.toString());  // 18014398509481984

注意:

BigInt 是一種新的數(shù)據(jù)原始(primitive)類型。

5. for-in機(jī)制


ECMAScript遺留了一個關(guān)于for-in循環(huán)順序的詳細(xì)描述大刊。在 ECMA-262 5rd Edition 中對遍歷機(jī)制又進(jìn)行了調(diào)整为迈,并未并且規(guī)定具體的規(guī)則,不同瀏覽器有不同的實(shí)現(xiàn)缺菌,這導(dǎo)致對屬性的遍歷順序存在不一致的問題。ES2020 中要求對象的遍歷實(shí)現(xiàn)上搜锰,各瀏覽器要保持一致伴郁。


6. 可選鏈(Optional chaining)


以前在處理多層對象屬性值獲取的時候,通常需要對各層級的屬性進(jìn)行校驗(yàn).

例如

let name = user && user.info && user.info.name

這是一種丑陋但又不得不做的前置校驗(yàn),否則很容易命中 Uncaught TypeError: Cannot read property… 這種錯誤蛋叼,這極有可能讓你整個應(yīng)用掛掉焊傅。

對此剂陡,ES2020 進(jìn)行了優(yōu)化,可以通過 ?. 來簡化校驗(yàn)狐胎。

?. 操作符與 . 類似鸭栖,兩者的區(qū)別在于,?. 在獲取對象屬性時握巢,如果其引用對象為 null 或 undefined晕鹊,則表達(dá)式會發(fā)生短路暴浦,直接返回 undefined溅话。

示例代碼如下:

// 1. 能正確找到屬性值
let user = {
    info:{
        name:"小明"
    }
}
var name = user?.info?.name;
console.log(name);   // 小明
?
// 2. 屬性值不存在
let user2 = {
    info:{
        city:"上海"
    }
}
var name2 = user2?.info?.name;
console.log(name2);   // undefined


7. 空值合并運(yùn)算符(Nullish coalescing Operator)


在JavaScript中我們經(jīng)常會遇到給某個變量或者對象的屬性添加默認(rèn)值

示例:

// 三目運(yùn)算符處理默認(rèn)值
const name = user.name ? user.name : "默認(rèn)名稱";
?
// 邏輯運(yùn)算符中的短路算法處理默認(rèn)值
const name = user.name || "默認(rèn)名稱" 

ES2020 新增了更簡潔的空值合并操作符(??),左側(cè)值為 null 或 undefined 時返回右側(cè)默認(rèn)值

const name = user.name ?? "默認(rèn)名稱" 

但對于邏輯或操作符來說歌焦,''飞几、0 都會轉(zhuǎn)化為 false,容易產(chǎn)生邏輯錯誤独撇。在業(yè)務(wù)上屑墨,大多是是想判斷變量是否為 undefined 或者 null。

因此要注意,

// user.name的值會有可能會進(jìn)行隱式類型轉(zhuǎn)行,為0的時候,也會只用默認(rèn)值
const name = user.name || "默認(rèn)名稱" ;
?
// ES2020新增的?? 運(yùn)算符 有且僅當(dāng)user.name的為null或者undefined時
// 才會啟用默認(rèn)值
const name = user.name ?? "默認(rèn)名稱" 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纷铣,一起剝皮案震驚了整個濱河市绪钥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌关炼,老刑警劉巖程腹,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異儒拂,居然都是意外死亡寸潦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門社痛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來见转,“玉大人,你說我怎么就攤上這事蒜哀≌扼铮” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵撵儿,是天一觀的道長乘客。 經(jīng)常有香客問我,道長淀歇,這世上最難降的妖魔是什么易核? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮浪默,結(jié)果婚禮上牡直,老公的妹妹穿的比我還像新娘缀匕。我一直安慰自己,他們只是感情好碰逸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布乡小。 她就那樣靜靜地躺著,像睡著了一般饵史。 火紅的嫁衣襯著肌膚如雪满钟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天约急,我揣著相機(jī)與錄音零远,去河邊找鬼。 笑死厌蔽,一個胖子當(dāng)著我的面吹牛牵辣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奴饮,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼纬向,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了戴卜?” 一聲冷哼從身側(cè)響起逾条,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎投剥,沒想到半個月后师脂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡江锨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年吃警,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啄育。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡酌心,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挑豌,到底是詐尸還是另有隱情安券,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布氓英,位于F島的核電站侯勉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏债蓝。R本人自食惡果不足惜壳鹤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饰迹。 院中可真熱鬧芳誓,春花似錦、人聲如沸啊鸭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赠制。三九已至赂摆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钟些,已是汗流浹背烟号。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留政恍,地道東北人汪拥。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像篙耗,于是被迫代替她去往敵國和親迫筑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353