ES2020 是 ECMAScript 對應 2020 年的版本。這個版本不像 ES6 (ES2015)那樣包含大量新特性。但也添加了許多有趣且有用的特性。javascript
本文以簡單的代碼示例來介紹 ES2020新特性。這樣,你能夠很快理解這些新功能,而不須要多麼複雜的解釋。更多優質文章請猛戳GitHub博客前端
可選鏈 可以讓咱們在查詢具備多個層級的對象時,再也不須要進行冗餘的各類前置校驗。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
當咱們查詢某個屬性時,常常會給沒有該屬性就設置一個默認的值,好比下面兩種方式:瀏覽器
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.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的支持狀況:
若是一個正則表達式在字符串裏面有多個匹配,如今通常使用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的支持狀況:
如今前端打包資源愈來愈大,前端應用初始化時根本不須要所有加載這些邏輯資源,爲了首屏渲染速度更快,不少時候都是動態導入(按需加載)模塊,好比懶加載圖片等,這樣能夠幫助您提升應用程序的性能。
其中按需加載這些邏輯資源都通常會在某一個事件回調中去執行:
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的支持狀況:
javascript 在 Math 上一直很糟糕的緣由之一是隻能安全的表示-(2^53-1)
至 2^53-1
範的值,即Number.MIN_SAFE_INTEGER
至Number.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 是一個全新的標準方法用來獲取全局 this 。以前開發者會經過以下的一些方法獲取:
過去獲取全局對象,可經過一個全局函數:
// 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的支持狀況: