ES2020,你需要知道的一切內容!


如何給JavaScript增加新的特性?

並非是Google,或者是其他權力巔峰的人。JavaScript規范由稱為TC39的委員會進行管理和迭代。TC39由各種開發人員,學術界人士和平台愛好者組成。

TC39每年約召開6次會議,大部分在美國,但在歐洲也舉行。他們與社區合作,接受有關JavaScript新功能的建議,並逐步處理JavaScript語言建議的四個“階段”。這四個階段如下:

 

 

Stage 0: strawman 一種推進ECMAScript發展的自由形式,任何TC39成員,或者注冊為TC39貢獻者的會員,都可以提交。通常通過針對TC39 ECMAScript GitHub存儲庫提高PR來完成此操作

Stage 1: proposal 該階段產生一個正式的提案。

  • 確定一個帶頭人來負責該提案,帶頭人或者聯合帶頭人必須是TC39的成員。
  • 描述清楚要解決的問題,解決方案中必須包含例子,API以及關於相關的語義和算法。
  • 潛在問題也應該指出來,例如與其他特性的關系,實現它所面臨的挑戰。
  • polyfill和demo也是必要的。

圍繞提案創建了一個公共GitHub存儲庫,其中包含示例,高級API,基本原理和潛在問題。

Stage 2: draft 草案是規范的第一個版本,與最終標准中包含的特性不會有太大差別。 草案之后,原則上只接受增量修改。

  • 草案中包含新增特性語法和語義的,盡可能的完善的形式說明,允許包含一些待辦事項或者占位符。
  • 必須包含2個實驗性的具體實現,其中一個可以是用轉譯器實現的,例如Babel。

“草案”階段意味着需要確定提案的所有語法和語義。這涉及使用您將在JavaScript規范本身中看到的正式規范語言描述提案功能。

Stage 3: candidate 候選階段,獲得具體實現和用戶的反饋。 此后,只有在實現和使用過程中出現了重大問題才會修改。

  • 規范文檔必須是完整的,評審人和ECMAScript的編輯要在規范上簽字。
  • 至少要有兩個符合規范的具體實現

在此階段,責任在於社區。開發人員應使用該功能並提供反饋,這只有通過在實際開發中使用它才能實現。

Stage 4: finished 已經准備就緒,該特性會出現在年度發布的規范之中。

  • 通過Test 262驗收測試
  • 有2個通過測試的實現,以獲取使用過程中的重要實踐經驗。
  • ECMAScript的編輯必須規范上的簽字。

塵埃落定。該建議已在社區中的實際實施中得到了很好的測試。本提案將包含在下一版ECMAScript標准中,並將被數以百萬計的人使用。

下面就是es2020新特性的介紹!

String.prototype.matchAll

String.prototype.matchAll是一個實用函數,用於獲取特定正則表達式的所有匹配項(包括捕獲組,這將在后面說明)。在ES2020之前如何解決此問題?讓我們來看一個簡單的示例並進行迭代:

const test = "climbing, oranges, jumping, flying, carrot"; 復制代碼

目標是獲取所有以ing結尾的單詞,並且返回他們去掉ing的動詞格式

  • 在字符串中搜索以“ ing”結尾的任何單詞(例如“ climbing”)
  • 捕獲單詞中“ ing”之前的所有字母(例如“ climb”)
  • 返回字符串

為了達到目的,我們使用下面的正則:

const regex = /([a-z]*)ing/g; 復制代碼

正則表達式很難,讓我們對其分解,了解每一部分的原理。

  • ([a-z]*)-匹配任何連續包含字母a到z的字符串。我們將其包裝在括號中(),以使其成為“捕獲組”。顧名思義,捕獲組就是“捕獲”與該特定部分匹配的字符組。在我們的示例中,我們希望匹配所有以“ ing”結尾的單詞,但是我們真正想要的是之前的字母,因此使用捕獲組。
  • ing -僅匹配以“ ing”結尾的字符串。
  • /g-全局搜索。搜索整個輸入字符串。不要在第一次匹配成功后就停下來。

String.prototype.match

我們希望通過正則表達式查找動詞。JavaScript中的match函數可以傳入正則表達式。

const test = "climbing, oranges, jumping, flying, carrot"; const regex = /([a-z]*)ing/g; test.match(regex); // ["climbing", "jumping", "flying"] 復制代碼

但這並不是我們想要的。它返回了完整的單詞,而不只是動詞!發生這種情況是因為match不支持使用/g標志捕獲組。match在不需要使用捕獲組的時候很好用,但現在似乎不太適合。

RegExp.prototype.exec

exec方法在正則表達式本身上執行,而不是在類似字符串上執行matchexec支持捕獲組,但是使用的API稍顯笨拙。您必須不斷exec在正則表達式上反復調用以獲取下一個匹配項。這要求我們創建一個無限循環並持續調用,exec執行到沒有匹配項為止。

const regex = /([a-z]*)ing/g;

const matches = [];

while (true) { const match = regex.exec(test); if (match === null) break; matches.push(match[1]); } matches // ["climb", "jump", "fly"] 復制代碼

這種方法是可以滿足需求的,但是有點混亂不清晰。這樣做的主要原因有兩個:

  • 僅當/g標志設置在末尾時,它才執行預期的操作。如果您將正則表達式作為變量或參數傳遞,這可能會引起混淆。
  • 使用/g標志時,RegExp對象是有狀態的,並存儲對其最后匹配項的引用。而這一點有可能導致bug,如果你重復且不同的調用它。

使用String.prototype.matchAll

終於,我們到了。String.prototype.matchAll這將使我們的生活更加輕松,並提供一個簡單的解決方案來支持捕獲組,並返回一個可迭代的數組,該數組可以擴展為數組。讓我們將上面的代碼重構使用matchAll。

const test = "climbing, oranges, jumping, flying, carrot"; const regex = /([a-z]*)ing/g; const matches = [...test.matchAll(regex)]; const result = matches.map(match => match[1]); result // ["climb", "jump", "fly"] 復制代碼

我們得到一個二維數組,第一個元素中的單詞全匹配**('climbing'),第二個元素中的捕獲組('climb')**。通過迭代並保留第二個元素,終於我們得到想要的結果。

動態import()

由於webpack的支持,這是您可能已經熟悉的一種方式。並且在生產JavaScript應用程序中經常使用它來進行“代碼拆分”。代碼拆分在單個頁面應用程序中非常強大。在許多情況下,可以大大加快初始頁面加載時間。

動態導入語法允許我們將import作為能夠返回promise的函數進行調用。這對於在代碼運行時動態加載模塊特別有用。例如,您可能想基於代碼中的某些邏輯來加載某個組件或模塊。

// JavaScript for side panel is loaded const sidePanel = await import("components/SidePanel"); sidePanel.open() 復制代碼

還支持插值。

async function openSidePanel(type = "desktop") { // JavaScript for desktop side panel is loaded const sidePanel = await import(`components/${type}/SidePanel`); sidePanel.open(); } 復制代碼

這個新功能增強了我們應用程序的性能。我們不必預先加載所有的JavaScript。動態導入使我們能夠僅加載所需數量的JS控件,性能上極大提升。

BigInt

 

 

JavaScript可以處理的最大數量為2^53。就是這樣9007199254740991,或者您可以使用更好記一點的Number.MAX_SAFE_INTEGER

當你數字超過MAX_SAFE_INTEGER時會發生什么?

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 - wut
console.log(Number.MAX_SAFE_INTEGER + 3); // 9007199254740994 - WUT
復制代碼

BigInt是ES2020中新增的類型,用於解決此問題。要將number或者string轉換為BigInt,可以使用BigInt構造函數,也可以n在其末尾添加a 。因此,要修正上面的示例,在將2加到后得到相同的值Number.MAX_SAFE_INTEGER

BigInt(Number.MAX_SAFE_INTEGER) + 2n; // 9007199254740993n ✅
復制代碼

誰需要這些數字呢?

您可能會驚訝於在軟件開發中擁有如此龐大的數字非常普遍。比如時間戳和唯一標識符就可以是這么大的數字。

例如,Twitter使用如此大的整數作為推文的唯一鍵。如果您嘗試將JavaScript存儲為不帶數字的數字,則會在JavaScript應用程序中看到奇怪的錯誤BigInt。您將不得不使用第三方社區包,或者將它們存儲為字符串。這也是JavaScript開發人員在BigInt不支持的環境中解決此問題的常用解決方案。

Promise.allSettled

假設您正在參加考試。收到結果后,您發現您正確回答了99%的問題。在大多數生活領域中,您都會充滿對勝利的希望。不過,在這種情況下,您依然會在得分中收到一個大紅色的叉,告訴您您失敗了。

這就是Promise.all的工作方式。Promise.all接受一系列承諾,並同時獲取其結果。如果它們全部成功,您的Promise.all成功。如果一項或多項失敗,您的Promise就會被reject。在某些情況下,您可能需要這種處理方式,但事實上並不總是這樣。

引入Promise.allSettled

ES2020的Promise.allSettled在考試方面可要比Promise.all好得多。它將使您輕拍一下,並告訴您不要擔心1%的reject

Promise出現時,無論它被認為是resolverejectPromise.allSettled允許我們傳遞一系列的Promise,這些Promise將在全部結束后,Promise的返回值是一個裝滿Promise結果的數組。讓我們看一個例子:

const promises = [
  fetch('/api1'), fetch('/api2'), fetch('/api3'), ]; Promise.allSettled(promises). then((results) => results.forEach((result) => console.log(result.status))); // "fulfilled" // "fulfilled" // "rejected" 復制代碼

globalThis

globalThis 是一個全新的標准方法用來獲取全局 this 。之前開發者會通過如下的一些方法獲取:

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

由於Js的通用性,相同的JavaScript代碼可以在NodeJS的客戶端和服務器上運行。這提出了一系列特殊的挑戰。

一個是全局對象,可以從任何運行的代碼段中訪問它。window在瀏覽器中,但globalNode中。編寫訪問此全局對象的通用代碼依賴於一些條件邏輯,這些條件邏輯可能看起來像這樣(蒙住眼睛)。

(typeof window !== "undefined" ? window : (typeof process === 'object' && typeof require === 'function' && typeof global === 'object') ? global : this); 復制代碼

值得慶幸的是,ES2020帶來了globalThis全局變量。現在可以放松的不去考慮windowglobal而統一前端或后端代碼。

globalThis.something = "Hello"; // Works in Browser and Node. 復制代碼

for-in的學問

for (x in obj) ... 是在很多時候都超級有用的語法,主要是遍歷對象的key值。

for (let key in obj) { console.log(key); } 復制代碼

該提議與在循環中迭代元素的順序和語義有關。在提出這個之前,大多數JavaScript引擎已經應用了常識,所有主流瀏覽器都按照定義它們的順序遍歷對象的屬性。但是,有些細微差別。這些主要涉及更高級的功能,例如代理。for..in循環語義從一開始就沒有包含在JavaScript規范中,但是該提議可確保每個人在for..in工作方式上都具有一致的參考點。

可選鏈操作符(Optional Chaining)

可選鏈接可能是相當長一段時間以來JavaScript中最受期待的功能之一。在對更干凈的JavaScript代碼的影響方面,這一得分非常高!!!

當檢查嵌套對象內部的屬性時,通常必須檢查中間對象的存在。讓我們來看一個例子:

const test = { name: "foo", age: 25, address: { number: 44, street: "Sesame Street", city: { name: "Fake City", lat: 40, lon: 74 } } } // when we want to check for the name of the city if (test.address.city.name) { console.log("City name exists!"); } // City Name exists! 復制代碼

這是一個成功的例子!但是在開發中,不能總是依靠幸福的曙光照耀我們。有時中間的值會不存在。讓我們看同樣的例子,但是沒有給city定義值。

const test = { name: "foo", age: 25, address: { number: 44, street: "Sesame Street" } } if (test.address.city.name) { console.log("City name exists!"); } // TypeError: Cannot read property 'name' of undefined 復制代碼

我們的代碼已經報錯了。這是因為我們試圖訪問nametest.address.city,但是這是一個undefined。當嘗試讀取undefined上的屬性時TypeError肯定會拋出以上內容。那我們該如何解決?在之前許多JavaScript代碼中,您將看到以下解決方案:

const test = { name: "foo", age: 25, address: { number: 44, street: "Sesame Street" }, } if (test.address && test.address.city && test.address.city.name) { console.log("City name exists!"); } // no TypeError thrown! 復制代碼

我們的代碼現在可以運行了,但是我們不得不在出bug那兒寫很多代碼來解決問題。我們按理來說可以做得更好!ES2020的可選鏈接運算符使您可以使用新的?語法檢查對象深處是否存在值。這是使用可選鏈接運算符重寫的上述示例:

const test = { name: "foo", age: 25, address: { number: 44, street: "Sesame Street" }, } // much cleaner. if (test?.address?.city?.name) { console.log("City name exists!"); } // no TypeError thrown! 復制代碼

看起來不錯。我們將十分長的&&鏈,濃縮為更加簡潔易讀的可選鏈運算符。如果鏈中的任何值是null或者 undefined,則表達式僅返回undefined

可選的鏈接運算符非常強大。請看以下示例可以使用它的其他方式:

const nestedProp = obj?.['prop' + 'Name']; // computed properties const result = obj.customMethod?.(); // functions const arrayItem = arr?.[42]; // arrays 復制代碼

空位合並運算符(Nullish coalescing Operator)

空位合並運算符是一個非常簡單的名稱,聽起來很花哨。此功能使我們能夠檢查一個值是否為nullundefined,如果是,則默認為另一個值,僅此而已。

為什么這有用?讓我們假設一下,你的JavaScript中有五個虛值。

  • null
  • undefined
  • 空字符串 ""
  • 0
  • 沒有數字-NaN

我們可能有一些要檢查數值的代碼。我們想為球隊中的球員分配一個小隊號碼。如果他們已經有小隊號碼,我們將保留該號碼。否則,我給他們一個叫"unssigned"的值。

const person = {
  name: "John", age: 20, squadNumber: 100 }; const squadNumber = person.squadNumber || "unassigned"; console.log(`${person.name}s squad number is ${squadNumber}`); // "Johns squad number is 100" 復制代碼

此代碼可以正常工作。但是,讓我們從一個稍微不同的角度來考慮。如果我們的person0,該怎么辦?

const person = {
  name: "Dave", age: 30, squadNumber: 0 }; const squadNumber = person.squadNumber || "unassigned"; console.log(`${person.name}s squad number is ${squadNumber}`); // "Daves squad number is unassigned" 復制代碼

這是不對的。Dave已經為球隊效力了多年。我們的代碼有一個錯誤。發生這種情況是因為0,導致我們false條件的||被調用。在此示例中,對結果值的檢查存在問題。您當然可以通過以下操作解決此問題:

const person = {
  name: "Dave", age: 30, squadNumber: 0 }; const squadNumber = person.squadNumber >= 0 ? person.squadNumber : "unassigned"; console.log(`${person.name}s squad number is ${squadNumber}`); // "Daves squad number is 0" 復制代碼

這是一個還可以的解決方案,但我們可以使用空位合並運算符來解決。

運算符??可以更好地確保我們的值是nullundefined

const person = {
  name: "Dave", age: 30, squadNumber: 0 }; // Nullish Coalescing Operator // If person.squadNumber is null or undefined // set squadNumber to unassigned const squadNumber = person.squadNumber ?? "unassigned"; console.log(`${person.name}s squad number is ${squadNumber}`); // "Daves squad number is 0" 復制代碼

import.meta

import.meta是一個給JavaScript模塊暴露特定上下文的元數據屬性的對象。它包含了這個模塊的信息,比如說這個模塊的URL。

如果您熟悉Node,則可以通過__dirname__filename屬性與CommonJS一起使用此功能。

const fs = require("fs"); const path = require("path"); // resolves data.bin relative to the directory of this module const bytes = fs.readFileSync(path.resolve(__dirname, "data.bin")); 復制代碼

那瀏覽器呢?這里import.meta將會變得有用。如果要從瀏覽器中運行的JavaScript模塊導入相對路徑,則可以讓import.meta這樣做:

// Will import cool-image relative to where this module is running. const response = await fetch(new URL("../cool-image.jpg", import.meta.url)); 復制代碼

此功能對開發第三方庫的作者那可是非常有用了,因為他們不知道他們的代碼將在什么地方以什么方式運行的。

結論

總而言之,ECMAScript規范中添加的最新功能為不斷發展和發展的JavaScript生態系統增加了更多實用性,靈活性和強大功能。看到社區繼續以如此快的速度蓬勃發展和進步,真的令人鼓舞和激動。

您可能在想:“這些聽起來不錯,但是我如何在我的項目里使用ES2020功能呢?

什么時候,如何使用這些東西?

現在就可以使用它!在大多數現代瀏覽器和Node的最新版本中,支持所有的功能。caniuse.com是另一個很棒的網站,可用於檢查跨瀏覽器和Node的ES2020新增功能的兼容性級別。

如果需要在較舊的瀏覽器或Node版本上使用這些功能,則需要babel / typescript

希望你學到了一些東西。謝謝閱讀!


作者:黃梵高
鏈接:https://juejin.im/post/5eba14d1e51d4540bb61748d
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM