Promise 組合子
自從在 ES2015 引入 Promise 以來,JavaScript 就支持了兩種 Promise 組合子:靜態方法 Promise.all
和 Promise.race
。
目前有兩個新的提案正在標準化過程中:Promise.allSettled
和 Promise.any
。隨著這些新增內容,JavaScript 共有四種 Promise 組合子,每一種都支持不同的使用場景。
自從在 ES2015 引入 Promise 以來,JavaScript 就支持了兩種 Promise 組合子:靜態方法 Promise.all
和 Promise.race
。
目前有兩個新的提案正在標準化過程中:Promise.allSettled
和 Promise.any
。隨著這些新增內容,JavaScript 共有四種 Promise 組合子,每一種都支持不同的使用場景。
Array.prototype.flat
此範例中的陣列是多層嵌套的:它包含一個陣列,而這個陣列又包含另一個陣列。
const array = [1, [2, [3]]];
// ^^^^^^^^^^^^^ 外層陣列
// ^^^^^^^^ 內層陣列
// ^^^ 最內層陣列
Array#flat
回傳一個展平後的陣列。
array.flat();
// → [1, 2, [3]]
// …等同於:
array.flat(1);
// → [1, 2, [3]]
預設的展平深度是 1
,但您可以傳入任何數字值來遞迴展平到該深度。若要持續展平直到結果不再包含嵌套陣列,可以使用 Infinity
。
// 持續遞迴展平直到陣列不再包含嵌套陣列:
array.flat(Infinity);
// → [1, 2, 3]
這個方法為什麼叫做 Array.prototype.flat
而不是 Array.prototype.flatten
呢?閱讀我們的 #SmooshGate 撰寫內容來了解!
Array.prototype.flatMap
以下是另一個範例。我們有一個 duplicate
函數,它接受一個值並回傳一個包含該值兩次的陣列。如果我們將 duplicate
套用到陣列中的每個值,我們會得到一個嵌套陣列。
const duplicate = (x) => [x, x];
[2, 3, 4].map(duplicate);
// → [[2, 2], [3, 3], [4, 4]]
接著您可以對結果呼叫 flat
來展平陣列:
[2, 3, 4].map(duplicate).flat(); // 🐌
// → [2, 2, 3, 3, 4, 4]
由於此模式在函數式編程中相當常見,因此現在有一個專屬的 flatMap
方法。
[2, 3, 4].flatMap(duplicate); // 🚀
// → [2, 2, 3, 3, 4, 4]
flatMap
比起分別執行 map
和 flat
更加高效。
對 flatMap
的使用案例感興趣嗎?請查看 Axel Rauschmayer 的解釋。
Array#{flat,flatMap}
支援大型數字字面值難以讓人眼快速解析,尤其是當數字中有許多重複的數字時:
1000000000000
1019436871.42
為了提升可讀性,一項新的 JavaScript 語言特性允許在數字字面值中使用底線作為分隔符。因此,可以將上述數字重新編寫,以每千位分組為例:
在字串中重複套用同一個正則表達式以獲取所有匹配的情況並不罕見。某種程度上,這已經可以通過使用 String#match
方法實現。
在這個例子中,我們找到所有僅由十六進位數字組成的字,然後記錄每個匹配項:
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.match(regex)) {
console.log(match);
}
// 輸出:
//
// 'DEADBEEF'
// 'CAFE'
然而,這只會給你匹配的 子字串。通常,你不僅想要子字串,還希望獲取附加資訊,如每個子字串的索引,或者每次匹配時的捕捉群組。
這可以通過撰寫自己的迴圈並手動跟蹤匹配物件來實現,但這有點麻煩且不太方便:
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
let match;
while (match = regex.exec(string)) {
console.log(match);
}
// 輸出:
//
// [ 'DEADBEEF', index: 19, input: 'Magic hex numbers: DEADBEEF CAFE' ]
// [ 'CAFE', index: 28, input: 'Magic hex numbers: DEADBEEF CAFE' ]
新的 String#matchAll
API 使這變得前所未有的簡單:現在你可以撰寫一個簡單的 for
-of
迴圈以獲取所有匹配物件。
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.matchAll(regex)) {
console.log(match);
}
// 輸出:
//
// [ 'DEADBEEF', index: 19, input: 'Magic hex numbers: DEADBEEF CAFE' ]
// [ 'CAFE', index: 28, input: 'Magic hex numbers: DEADBEEF CAFE' ]
String#matchAll
對於具有捕捉群組的正則表達式特別有用。它會提供每個匹配的完整資訊,包括捕捉群組。
const string = 'Favorite GitHub repos: tc39/ecma262 v8/v8.dev';
const regex = /\b(?<owner>[a-z0-9]+)\/(?<repo>[a-z0-9\.]+)\b/g;
for (const match of string.matchAll(regex)) {
console.log(`${match[0]} at ${match.index} with '${match.input}'`);
console.log(`→ owner: ${match.groups.owner}`);
console.log(`→ repo: ${match.groups.repo}`);
}
現代的網絡應用通常使用包含動態數據的列表。例如,一個相片查看應用可能顯示如下內容:
此相片包括 Ada、Edith、和 Grace。
一款文字遊戲可能會顯示另一種類型的列表:
選擇你的超能力:隱形、心靈控制、或 共情能力。
由於每種語言的列表格式化習慣和詞語各不相同,實現一個本地化的列表格式化器並非易事。不僅需要獲取所有希望支持語言中的相關詞語(如上例中的 “and” 或 “or”),還需要對所有這些語言的格式化習慣進行編碼!Unicode CLDR 提供這些數據,但要在 JavaScript 中使用它,這些數據需嵌入並隨其他庫代碼一起傳遞。這樣不幸會增加庫的捆綁大小,進而對加載時間、解析/編譯成本及內存消耗造成負面影響。
在 JavaScript 模組 中,先前已經可以使用以下語法:
import * as utils from './utils.mjs';
然而,並沒有對稱的 export
語法……直到現在:
export * as utils from './utils.mjs';
這相當於以下:
import * as utils from './utils.mjs';
export { utils };
多個提案擴展了現有的 JavaScript 類別語法,提供了新功能。本文章解釋了 V8 v7.2 和 Chrome 72 中新增的公開類別字段語法,以及即將推出的私有類別字段語法。
以下是一個創建名為 IncreasingCounter
的類別實例的程式碼範例:
const counter = new IncreasingCounter();
counter.value;
// 記錄 '獲取目前的值!'
// → 0
counter.increment();
counter.value;
// 記錄 '獲取目前的值!'
// → 1
請注意,存取 value
會先執行某些程式碼(例如,記錄訊息)然後才返回結果。現在問問自己,您會如何在 JavaScript 中實作這個類別?🤔
以下是使用 ES2015 類別語法實作 IncreasingCounter
的方式:
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('獲取目前的值!');
return this._count;
}
increment() {
this._count++;
}
}
此類別在原型上安裝了 value
取得器和 increment
方法。更有趣的是,這個類別有一個建構子會創建 _count
實例屬性並將其預設值設定為 0
。我們目前傾向使用底線前綴來表示 _count
不應直接被類別的用戶使用,但這只是一種慣例;它並不是語言強制的 真正 “私有”屬性。
JSON.stringify
之前的規範是當輸入包含任何孤立代理項時,返回格式不良的 Unicode 字串:
JSON.stringify('\uD800');
// → '"�"'
“格式良好的 JSON.stringify
”提案 修改了 JSON.stringify
,使其對孤立代理項輸出轉義序列,令其輸出有效 Unicode(並且可在 UTF-8 中表示):