ES2020新特性

前言

ES2020 是 ECMAScript 對應 2020 年的版本。這個版本不像 ES6 (ES2015)那樣包含大量新特性。但也添加了許多有趣且有用的特性。javascript

本文以簡單的代碼示例來介紹 ES2020新特性。這樣,你能夠很快理解這些新功能,而不須要多麼複雜的解釋。更多優質文章請猛戳GitHub博客前端

可選鏈操做符(Optional Chaining)

可選鏈 可以讓咱們在查詢具備多個層級的對象時,再也不須要進行冗餘的各類前置校驗。java

平常開發中,當須要訪問嵌套在對象內部好幾層的屬性時,可能就會獲得臭名昭著的錯誤Uncaught TypeError: Cannot read property...,這種錯誤,讓整段程序運行停止。 node

因而,你就要修改你的代碼來處理來處理屬性鏈中每個可能的undefined對象,好比:git

let nestedProp = obj && obj.first && obj.first.second;
複製代碼

在訪問 obj.first.second 以前,要先確認 obj 和 obj.first 的值非 null(且不是 undefined)。github

有了可選鏈式調用 ,能夠大量簡化相似繁瑣的前置校驗操做,並且更安全:正則表達式

let nestedProp = obj?.first?.second;
複製代碼

若是obj或obj.first是null/undefined,表達式將會短路計算直接返回undefined。數組

可選鏈操做符的支持狀況: promise

空位合併操做符(Nullish coalescing Operator)

當咱們查詢某個屬性時,常常會給沒有該屬性就設置一個默認的值,好比下面兩種方式:瀏覽器

let c = a ? a : b // 方式1
let c = a || b // 方式2
複製代碼

這兩種方式有個明顯的弊端,它都會覆蓋全部的假值,如(0, '', false),這些值多是在某些狀況下有效的輸入。

let x = {
  profile: {
    name: '浪裏行舟',
    age: ''
  }
}
console.log(x.profile.age || 18) //18
複製代碼

上例中age的屬性爲空字符串,卻被等同爲假值,爲了解決這個問題,ES2020誕生了個新特性--空位合併操做符,用 ?? 表示。若是表達式在??的左側運算符求值爲 undefined 或 null,就返回其右側默認值。

let c = a ?? b;
// 等價於let c = a !== undefined && a !== null ? a : b;
複製代碼

例若有如下代碼:

const x = null;
const y = x ?? 500;
console.log(y); // 500
const n = 0
const m = n ?? 9000;
console.log(m) // 0
複製代碼

空位合併操做符的支持狀況:

Promise.allSettled

咱們知道 Promise.all 具備併發執行異步任務的能力。但它的最大問題就是若是參數中的任何一個promise爲reject的話,則整個Promise.all 調用會當即終止,並返回一個reject的新的 Promise 對象。

const promises = [
 Promise.resolve(1),
 Promise.resolve(2),
 Promise.reject('error')
];

Promise.all(promises)
 .then(responses => console.log(responses))
 .catch(e => console.log(e)) // "error"
複製代碼

假若有這樣的場景:一個頁面有三個區域,分別對應三個獨立的接口數據,使用 Promise.all 來併發請求三個接口,若是其中任意一個接口出現異常,狀態是reject,這會致使頁面中該三個區域數據全都沒法出來,這個情況咱們是沒法接受,Promise.allSettled的出現就能夠解決這個痛點:

Promise.allSettled([
  Promise.reject({ code: 500, msg: '服務異常' }),
  Promise.resolve({ code: 200, list: [] }),
  Promise.resolve({ code: 200, list: [] })
]).then(res => {
  console.log(res)
  /*
        0: {status: "rejected", reason: {…}}
        1: {status: "fulfilled", value: {…}}
        2: {status: "fulfilled", value: {…}}
    */
  // 過濾掉 rejected 狀態,儘量多的保證頁面區域數據渲染
  RenderContent(
    res.filter(el => {
      return el.status !== 'rejected'
    })
  )
})
複製代碼

Promise.allSettled跟Promise.all相似, 其參數接受一個Promise的數組, 返回一個新的Promise, 惟一的不一樣在於, 它不會進行短路, 也就是說當Promise所有處理完成後,咱們能夠拿到每一個Promise的狀態, 而不論是否處理成功。

Promise.allSettled的支持狀況:

String.prototype.matchAll

若是一個正則表達式在字符串裏面有多個匹配,如今通常使用g修飾符或y修飾符,在循環裏面逐一取出。

function collectGroup1 (regExp, str) {
  const matches = []
  while (true) {
    const match = regExp.exec(str)
    if (match === null) break
    matches.push(match[1])
  }
  return matches
}
console.log(collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`)) // [ 'foo', 'bar', 'baz' ] 複製代碼

值得注意的是,若是沒有修飾符 /g, .exec() 只返回第一個匹配。如今經過String.prototype.matchAll方法,能夠一次性取出全部匹配。

function collectGroup1 (regExp, str) {
  let results = []
  for (const match of str.matchAll(regExp)) {
    results.push(match[1])
  }
  return results
}
console.log(collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`)) // ["foo", "bar", "baz"] 複製代碼

上面代碼中,因爲string.matchAll(regex)返回的是遍歷器,因此能夠用for...of循環取出。

String.prototype.matchAll的支持狀況:

Dynamic import

如今前端打包資源愈來愈大,前端應用初始化時根本不須要所有加載這些邏輯資源,爲了首屏渲染速度更快,不少時候都是動態導入(按需加載)模塊,好比懶加載圖片等,這樣能夠幫助您提升應用程序的性能。

其中按需加載這些邏輯資源都通常會在某一個事件回調中去執行:

el.onclick = () => {
  import('/modules/my-module.js')
    .then(module => {
      // Do something with the module.
    })
    .catch(err => {
      // load error;
    })
}
複製代碼

import()能夠用於script腳本中,import(module) 函數能夠在任何地方調用。它返回一個解析爲模塊對象的 promise。

這種使用方式也支持 await 關鍵字。

let module = await import('/modules/my-module.js');
複製代碼

經過動態導入代碼,您能夠減小應用程序加載所需的時間,並儘量快地將某些內容返回給用戶。

Dynamic import的支持狀況:

BigInt

javascript 在 Math 上一直很糟糕的緣由之一是隻能安全的表示-(2^53-1)2^53-1 範的值,即Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER,超出這個範圍的整數計算或者表示會丟失精度。

var num = Number.MAX_SAFE_INTEGER;  // -> 9007199254740991

num = num + 1; // -> 9007199254740992

// 再次加 +1 後沒法正常運算
num = num + 1; // -> 9007199254740992

// 兩個不一樣的值,卻返回了true
9007199254740992 === 9007199254740993  // -> true
複製代碼

因而 BigInt 應運而生,它是第7個原始類型,可安全地進行大數整型計算。 你能夠在BigInt上使用與普通數字相同的運算符,例如 +, -, /, *, %等等。

建立 BigInt 類型的值也很是簡單,只須要在數字後面加上 n 便可。例如,123 變爲 123n。也可使用全局方法 BigInt(value) 轉化,入參 value 爲數字或數字字符串。

const aNumber = 111;
const aBigInt = BigInt(aNumber);
aBigInt === 111n // true
typeof aBigInt === 'bigint' // true
typeof 111 // "number"
typeof 111n // "bigint"
複製代碼

只要在數字末尾加上 n,就能夠正確計算大數了:

1234567890123456789n * 123n;
// -> 151851850485185185047n
複製代碼

不過有一個問題,在大多數操做中,不能將 BigInt與Number混合使用。比較Number和 BigInt是能夠的,可是不能把它們相加。

1n < 2 
// true

1n + 2
// Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
複製代碼

BigInt的支持狀況:

globalThis

globalThis 是一個全新的標準方法用來獲取全局 this 。以前開發者會經過以下的一些方法獲取:

  • 全局變量 window:是一個經典的獲取全局對象的方法。可是它在 Node.js 和 Web Workers 中並不能使用
  • 全局變量 self:一般只在 Web Workers 和瀏覽器中生效。可是它不支持 Node.js。一些人會經過判斷 self 是否存在識別代碼是否運行在 Web Workers 和瀏覽器中
  • 全局變量 global:只在 Node.js 中生效

過去獲取全局對象,可經過一個全局函數:

// ES10以前的解決方案
const 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')
}

// ES10內置
globalThis.Array(0,1,2) // [0,1,2]

// 定義一個全局對象v = { value:true } ,ES10用以下方式定義
globalThis.v = { value:true }
複製代碼

globalThis 目的就是提供一種標準化方式訪問全局對象,有了 globalThis 後,你能夠在任意上下文,任意時刻都能獲取到全局對象。

若是您在瀏覽器上,globalThis將爲window,若是您在Node上,globalThis則將爲global。所以,再也不須要考慮不一樣的環境問題。

// worker.js
globalThis === self
// node.js
globalThis === global
// browser.js
globalThis === window
複製代碼

新提案也規定了,Object.prototype 必須在全局對象的原型鏈中。下面的代碼在最新瀏覽器中已經會返回 true 了:

Object.prototype.isPrototypeOf(globalThis); // true
複製代碼

globalThis的支持狀況:

歡迎關注公衆號:前端工匠,你的成長咱們一塊兒見證!

參考文章

相關文章
相關標籤/搜索