在寫本文時,本文提到的新的 JavaScript 提案功能已進入第 4 階段,而且幾乎確定會包含在 ES2021 中。你已經能夠開始在 最新版本的瀏覽器,Node.js 和 Babel 中使用。前端
注意:ECMAScript 是 JavaScript 所基於的標準,由 TC39 委員會管理。ECMAScript 始終是一個不須要的名稱,這會使一切都對初學者感到困惑。人們常常談論 JavaScript 功能,但參考的是 ECMAScript 規範。git
更新特性github
_
)&&=
,||=
,??=
)WeakRef
和FinalizationRegistry
)大數字文字很難令人眼快速解析,尤爲是當有不少重複的數字時:正則表達式
1000000000000 1019436871.42
爲了提升可讀性,新的 JavaScript 語言功能 啓用了下劃線做爲數字文字中的分隔符。所以,上面的內容如今能夠重寫爲每千位數字,例如:編程
1_000_000_000_000 1_019_436_871.42
如今,更容易說出第一個數字是 1 萬億,而第二個數字大約是 10 億。api
數字分隔符有助於提升各類數字文字的可讀性:promise
// A decimal integer literal with its digits grouped per thousand: 1_000_000_000_000 // A decimal literal with its digits grouped per thousand: 1_000_000.220_720 // A binary integer literal with its bits grouped per octet: 0b01010110_00111000 // A binary integer literal with its bits grouped per nibble: 0b0101_0110_0011_1000 // A hexadecimal integer literal with its digits grouped by byte: 0x40_76_38_6A_73 // A BigInt literal with its digits grouped per thousand: 4_642_473_943_484_686_707n
它們甚至適用於八進制整數文字(儘管 我想不出 其中分隔符爲此類文字提供值 的示例):瀏覽器
// A numeric separator in an octal integer literal: 🤷♀️ 0o123_456
請注意,JavaScript 還具備不帶顯式 0o
前綴的八進制文字的舊式語法。例如,017 === 0o17
。在嚴格模式下或模塊內不支持此語法,而且在現代代碼中不該使用此語法。所以,這些文字不支持數字分隔符。使用 0o17
風格的文字代替。babel
自從 ES2015 中引入 Promise 以來,JavaScript 徹底支持兩種 Promise 組合器:靜態方法 Promise.all 和 Promise.race。less
目前有兩個新提案正在經過標準化流程:Promise.allSettled 和 Promise.any。有了這些添加,JavaScript 中將總共有四個諾言組合器,每一個組合器支持不一樣的用例。
如下是這四個組合器的概述:
Promise.allSettled 給你當全部輸入的諾言是一種信號結算,這意味着他們要麼履行或拒絕。若是您不在意承諾的狀態,而只是想知道工做什麼時候完成,不管它是否成功,這都是頗有用的。
例如,您能夠啓動一系列獨立的 API 調用,並使用 Promise.allSettled 它們來確保它們已所有完成,而後再執行其餘操做,例如刪除加載微調器:
const promises = [ fetch('/api-call-1'), fetch('/api-call-2'), fetch('/api-call-3'), ]; // Imagine some of these requests fail, and some succeed. await Promise.allSettled(promises); // All API calls have finished (either failed or succeeded). removeLoadingIndicator();
Promise.any
方法和 Promise.race
相似——只要給定的迭代中的一個 promise
成功,就採用第一個 promise
的值做爲它的返回值,但與 Promise.race
的不一樣之處在於——它會等到全部 promise
都失敗以後,才返回失敗的值:
const promises = [ fetch('/endpoint-a').then(() => 'a'), fetch('/endpoint-b').then(() => 'b'), fetch('/endpoint-c').then(() => 'c'), ]; try { const first = await Promise.any(promises); // Any of the promises was fulfilled. console.log(first); // → e.g. 'b' } catch (error) { // All of the promises were rejected. console.assert(error instanceof AggregateError); // Log the rejection values: console.log(error.errors); // → [ // <TypeError: Failed to fetch /endpoint-a>, // <TypeError: Failed to fetch /endpoint-b>, // <TypeError: Failed to fetch /endpoint-c> // ] }
此代碼示例檢查哪一個端點響應最快,而後將其記錄下來。只有當 全部 請求都失敗時,咱們才最終進入代碼 catch
塊,而後在其中處理錯誤。
Promise.any
拒絕能夠一次表明多個錯誤。 爲了在語言級別支持此功能,引入了一種新的錯誤類型,稱爲 AggregateError
。 除了上面示例中的基本用法外,還能夠以編程方式構造 AggregateError
對象,就像其餘錯誤類型同樣:
const aggregateError = new AggregateError([errorA, errorB, errorC], 'Stuff went wrong!');
此功能包含兩個高級對象 WeakRef
和 FinalizationRegistry
。根據使用狀況,這些接口能夠單獨使用,也能夠一塊兒使用。正確使用它們須要仔細考慮,若是可能,最好避免使用它們。
通常來講,在JavaScript中,對象的引用是強保留的,這意味着只要持有對象的引用,它就不會被垃圾回收。
const ref = { x: 42, y: 51 }; // 只要咱們訪問 ref 對象(或者任何其餘引用指向該對象),這個對象就不會被垃圾回收
目前在 Javascript 中,WeakMap 和 WeakSet 是弱引用對象的惟一方法:將對象做爲鍵添加到 WeakMap 或 WeakSet 中,是不會阻止它被垃圾回收的。
JavaScript 的 WeakMap 並非真正意義上的弱引用:實際上,只要鍵仍然存活,它就強引用其內容。WeakMap 僅在鍵被垃圾回收以後,才弱引用它的內容。
WeakRef 是一個更高級的 API,它提供了真正的弱引用,Weakref 實例具備一個方法 deref,該方法返回被引用的原始對象,若是原始對象已被收集,則返回 undefined 對象。
JavaScript 中對象的引用是強引用,WeakMap 和 WeakSet 能夠提供部分的弱引用功能,若想在 JavaScript 中實現真正的弱引用,能夠經過配合使用 WeakRef 和終結器(Finalizer)來實現。
WeakRef 是用來指目標對象不脫離垃圾收集保留它的對象。若是未經過垃圾回收回收目標對象,則 WeakRefs 能夠取消引用以容許訪問目標對象。
// Create a WeakRef object referring to a given target object const ref = new WeakRef(targetObject) // Return the WeakRef instance's target object, or undefined if the target object has been garbage-collected const obj = ref.deref()
使用 FinalizationRegistry 對象能夠在垃圾回收對象時請求回調。
// Create a registry object that uses the given callback const registry = new FinalizationRegistry([callback]) // Register an object with a registry instance so that if the object is garbage-collected, the registry's callback may get called registry.register(target, heldValue, [unregisterToken]) // Unregister a target object from a registry instance registry.unregister(unregisterToken)
當前,若是不使用全局正則表達式,就沒法替換字符串中子字符串的全部實例。與字符串參數一塊兒使用時,String.prototype.replace 僅影響首次出現。
String.prototype.replaceAll()
將爲開發人員提供一種簡單的方法來完成此常見的基本操做。
'aabbcc'.replaceAll('b', '.') // 'aa..cc' 'aabbcc'.replaceAll(/b/g, '.') // 'aa..cc'
支持與新的運營邏輯分配 &&=
,||=
和 ??=
。與它們的 數學和按位對應物不一樣,邏輯分配遵循其各自邏輯操做的短路行爲。僅當邏輯運算將評估右側時,它們才執行分配。
// falsy: false, 0, -0, 0n, "", null, undefined, and NaN // truthy: all values are truthy unless defined as falsy // nullish: null or undefined a ||= b // Logical OR assignment // Equivalent to: a || (a = b); // Only assigns if a is falsy a &&= b // Logical AND assignment // Equivalent to: a && (a = b); // Only assigns if a is truthy a ??= b // Logical nullish assignment // Equivalent to: a ?? (a = b); // Only assigns if a is nullish
帶有 &&
運算符的邏輯賦值運算符
僅當 LHS 值爲真時,纔將 RHS 變量值賦給 LHS 變量。
// Logical Assignment Operator with && operator let num1 = 5 let num2 = 10 num1 &&= num2 console.log(num1) // 10 // Line 5 can also be written as following ways // 1. num1 && (num1 = num2) // 2. if (num1) num1 = num2
帶有 ||
的運算符邏輯賦值運算符
僅當 LHS 值爲假時,纔將 RHS 變量值賦給 LHS 變量。
// Logical Assignment Operator with || operator let num1 let num2 = 10 num1 ||= num2 console.log(num1) // 10 // Line 5 can also be written as following ways // 1. num1 || (num1 = num2) // 2. if (!num1) num1 = num2
帶有 ??
運算符的邏輯賦值運算符
ES2020 引入了空值合併運算符,其也能夠與賦值運算符結合使用。
僅當 LHS 爲 undefined 或僅爲 null 時,纔將 RHS 變量值賦給 LHS 變量。
// Logical Assignment Operator with ?? operator let num1 let num2 = 10 num1 ??= num2 console.log(num1) // 10 num1 = false num1 ??= num2 console.log(num1) // false // Line 5 can also be written as following ways // num1 ?? (num1 = num2)
做爲開發人員,跟緊語言的新特性是很重要的。
以上將在 2021 年發佈的一些新功能,它們是進入第 4 階段的提案,幾乎能夠確定會包括在內,這些功能已經在最新的瀏覽器和 babel 中實現。
歡迎關注公衆號: 「全棧修煉」,回覆 「電子書」 便可以得到 160 本前端精華書籍哦。
參考文章:JavaScript Features in 2021
往期精文
經過閱讀本篇文章,若是有收穫的話,能夠點個贊和在看,這將會成爲我持續分享的動力,感謝~