跳至主要内容

頂層`await`

· 閱讀時間約 5 分鐘
Myles Borins ([@MylesBorins](https://twitter.com/MylesBorins))

頂層await使開發者能夠在 async 函數之外使用 await 關鍵字。它像是一個大的 async 函數,會讓其他import它的模組在開始評估它們的主體之前等待。

Nullish coalescing

· 閱讀時間約 7 分鐘
Justin Ridgewell

新的 Nullish 合併提案 (??) 添加了一個短路運算符,用於處理默認值。

你可能已經熟悉其他短路運算符 &&||。這兩個運算符處理“真值”和“假值”。假設代碼示例 lhs && rhs,如果 lhs(讀作 左側)是假值,該表達式求值為 lhs。否則,則求值為 rhs(讀作 右側)。而在代碼示例 lhs || rhs 中則相反。如果 lhs 是真值,該表達式求值為 lhs。否則,則求值為 rhs

可選鏈(Optional chaining)

· 閱讀時間約 5 分鐘
Maya Armyanova ([@Zmayski](https://twitter.com/Zmayski)),可選鏈的破壞者

在 JavaScript 中,長鏈的屬性訪問可能容易出錯,因為其中任何一步都可能評估為 nullundefined(也稱為“空值”)。在每一步進行屬性存在檢查,很容易變成深度嵌套的 if 語句或一個長長的 if 條件,複製屬性訪問的鏈路:

包括 JSON,即 JSON ⊂ ECMAScript

· 閱讀時間約 6 分鐘
Mathias Bynens ([@mathias](https://twitter.com/mathias))

隨著提案 JSON ⊂ ECMAScript,JSON 成為 ECMAScript 的語法子集。如果你對此感到驚訝,並非只有你一個!

舊的 ES2018 行為

在 ES2018 中,ECMAScript 的字串文本不能包含未轉義的 U+2028 行分隔符和 U+2029 段落分隔符字元,因為即使在該上下文中,它們仍被認為是行終結符:

// 包含原始 U+2028 字元的字串。
const LS = '
';
// → ES2018: 語法錯誤

// 一個由 `eval` 生成的,包含原始 U+2029 字元的字串:
const PS = eval('"\u2029"');
// → ES2018: 語法錯誤

這是有問題的,因為 JSON 字串_可以_包含這些字元。因此,開發者在嵌入有效的 JSON 到 ECMAScript 程式中時,必須實現特殊的後處理邏輯來處理這些字元。沒有這樣的邏輯,程式碼可能會有細微的錯誤,甚至導致安全問題

`Intl.NumberFormat`

· 閱讀時間約 4 分鐘
Mathias Bynens ([@mathias](https://twitter.com/mathias)) 與 Shane F. Carr

你可能已經熟悉 Intl.NumberFormat API,因為它在現代環境中已被支援了一段時間。

在其最基本的形式中,Intl.NumberFormat 讓您可以建立一個可重用的格式器實例,支援語系感知的數字格式化。就像其他 Intl.*Format API 一樣,格式器實例同時支持 formatformatToParts 方法:

`globalThis`

· 閱讀時間約 2 分鐘
Mathias Bynens ([@mathias](https://twitter.com/mathias))

如果你曾經為瀏覽器編寫 JavaScript,可能使用過 window 來訪問全域 this。在 Node.js 中,你可能使用過 global。如果你編寫了需要同時在這兩個環境中運作的代碼,可能會檢測哪個可用,然後使用它 —— 但隨著你要支持的環境和使用情境增加,需要檢查的標識符列表也會越來越長,事情很快就會變得難以控制:

弱引用與終結器

· 閱讀時間約 10 分鐘
Sathya Gunasekaran ([@_gsathya](https://twitter.com/_gsathya)), Mathias Bynens ([@mathias](https://twitter.com/mathias)), Shu-yu Guo ([@_shu](https://twitter.com/_shu)), 和 Leszek Swirski ([@leszekswirski](https://twitter.com/leszekswirski))

通常,在 JavaScript 中對物件的引用是 強引用,這意味著只要你擁有對該物件的引用,它就不會被垃圾回收機制回收。

const ref = { x: 42, y: 51 };
// 只要你能訪問 `ref`(或者其他任何對同一物件的引用),該物件就不會被垃圾回收機制回收。

目前,WeakMapWeakSet 是 JavaScript 中唯一可以弱引用物件的方式:將物件作為 WeakMapWeakSet 的鍵添加,並不會防止該物件被垃圾回收機制回收。

const wm = new WeakMap();
{
const ref = {};
const metaData = 'foo';
wm.set(ref, metaData);
wm.get(ref);
// → metaData
}
// 在這個區塊範圍內,我們不再有對 `ref` 的引用,因此它
// 現在可以被垃圾回收機制回收,儘管它是 `wm` 的一個鍵
// 且我們仍然可以訪問 `wm`。

穩定的 `Array.prototype.sort`

· 閱讀時間約 3 分鐘
Mathias Bynens ([@mathias](https://twitter.com/mathias))

假設你有一個狗狗的陣列,每隻狗有一個名字和一個評級。(如果這聽起來是個奇怪的例子,你應該知道,Twitter 上有一個專門做這件事的賬號……請不要深究!)

// 注意,陣列已按 `name` 字母序排序。
const doggos = [
{ name: 'Abby', rating: 12 },
{ name: 'Bandit', rating: 13 },
{ name: 'Choco', rating: 14 },
{ name: 'Daisy', rating: 12 },
{ name: 'Elmo', rating: 12 },
{ name: 'Falco', rating: 13 },
{ name: 'Ghost', rating: 14 },
];
// 按 `rating` 降序排序狗狗。
// (會就地更新 `doggos`。)
doggos.sort((a, b) => b.rating - a.rating);

`Symbol.prototype.description`

· 閱讀時間約 1 分鐘
Mathias Bynens ([@mathias](https://twitter.com/mathias))

JavaScript Symbol 在建立時可以給予一個描述:

const symbol = Symbol('foo');
// ^^^^^

以前,要以程式方式存取這個描述的唯一方法是透過 Symbol.prototype.toString() 間接取得:

const symbol = Symbol('foo');
// ^^^^^
symbol.toString();
// → 'Symbol(foo)'
// ^^^
symbol.toString().slice(7, -1); // 🤔
// → 'foo'

然而,這段程式碼看起來有點神秘,不太容易理解,並且違反了“表達意圖,而不是實作”的原則。上述技術也無法區分沒有描述的 Symbol (即 Symbol())和描述為空字串的 Symbol(即 Symbol(''))。

`Object.fromEntries`

· 閱讀時間約 4 分鐘
Mathias Bynens ([@mathias](https://twitter.com/mathias)), JavaScript whisperer

Object.fromEntries 是 JavaScript 內建函式庫的一個實用新增功能。在解釋它的功能之前,了解現有的 Object.entries API 會有所幫助。

Object.entries

Object.entries API 已經存在一段時間了。

對於物件中的每個鍵值對,Object.entries 會返回一個陣列,第一個元素是鍵,第二個元素是值。

Object.entries 尤其在與 for-of 結合使用時非常有用,因為它能讓你非常優雅地遍歷物件中的所有鍵值對:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

for (const [key, value] of entries) {
console.log(`The value of ${key} is ${value}.`);
}
// 日誌:
// x 的值是 42。
// y 的值是 50。

不幸的是,直到現在,還沒有一個簡單的方法可以將 entries 結果轉回到等效的物件。

Object.fromEntries

新的 Object.fromEntries API 執行了 Object.entries 的相反操作。這使得根據其 entries 重建物件變得簡單:

const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]

const result = Object.fromEntries(entries);
// → { x: 42, y: 50 }

一個常見的用例是轉換物件。現在你可以通過遍歷它的 entries,然後使用你可能已經熟悉的陣列方法來完成:

const object = { x: 42, y: 50, abc: 9001 };
const result = Object.fromEntries(
Object.entries(object)
.filter(([ key, value ]) => key.length === 1)
.map(([ key, value ]) => [ key, value * 2 ])
);
// → { x: 84, y: 100 }

在這個例子中,我們使用 filter 過濾物件來僅保留鍵長度為 1 的鍵,也就是僅保留鍵 xy,不包括鍵 abc。接著,我們用 map 遍歷剩下的 entries,並為每個返回更新的鍵值對。此例中,我們通過將值乘以 2 來使每個值加倍。最終結果是一個新物件,僅包含屬性 xy 及其新值。