Categories
程式開發

ES2020特性集塵埃落定


TC39委員會於近期批准了ECMAScript 2020(即ES2020)候選提案,即經審定最終添加到JavaScript語言中的特性集。 ES2020候選提案是今年六月提交ECMA大會(General Assembly)的審批匯總,其中的大部分新特性已在瀏覽器中得到實現,並已可被Babel JavaScript解析器轉碼(transpile)。

在ES2020規範中,為String對象引入了新的matchAll方法,該方法根據一個全局正則表達式生成所有匹配對象的一個迭代器;在語法上支持import(),使用動態描述符異步導入模塊;支持任意精度整型的BigInt類型;Promise新的組合器Promise.allSettled,它不會造成短路;提供訪問全局this值的通用操作方式globalThis;模塊內使用的export * as ns from ‘module’專用語法;進一步規範化的for-in枚舉屬性順序;模塊中可包含依賴於宿主環境上下文相關信息的import.meta特性;以及改進對空位(即null和undefined)處理的兩個新語法特性,即值選取操作符“空位合併”(nullish coalescing),和“可選鏈”(optional chaining),一種一旦所訪問或調用的值為空位時採取短路的訪問/調用操作符。

動態導入(Dynamic imports)特性用於動態加載由應用合併(Bundling)中代碼切分階段所生成的模塊。該特性已得到除IE11以外的大部分瀏覽器的支持。開發人員可在任何時間無條件(例如,不同於只在模塊頭部定義導入,而是可在代碼任何位置)使用import()方法異步導入以moduleSpecifier = dir + ‘my-math.mjs’方式動態構建的模塊,並返回一個Promise對象。示例代碼如下:

const dir = './lib/';
const moduleSpecifier = dir + 'my-math.mjs';

async function loadConstant() {
  const myMath = await import(moduleSpecifier);
  const result = myMath.LIGHTSPEED;
  assert.equal(result, 299792458);
  return result;
}

import.meta對像中包含了依賴於當前宿主環境的模塊元數據。當前其中最受開發人員關注的是url屬性,url給出了當前模塊文件的URL字符串。開發人員可使用該URL字符串去導入相關模塊,或是根據模塊當前信息有條件地執行一些操作。 ES2020提案中給出瞭如下示例代碼,獲取當前模塊對應的hamster.jpg文件。

(async () => {
  const response = await fetch(new URL("../hamsters.jpg", import.meta.url));
  const blob = await response.blob();

  const size = import.meta.scriptElement.dataset.size || 300;

  const image = new Image();
  image.src = URL.createObjectURL(blob);
  image.width = image.height = size;

  document.body.appendChild(image);
})();

當該模塊加載的時候,無論模塊的加載位置在哪裡,都會加載同級目錄下的一個hamsters.jpg文件,並顯示該圖片。圖片文件的大小可在導入時使用JavaScript元素設定,例如:

關鍵字globalThis支持開發人員在編寫可移植ECMAScript代碼時訪問全局對象,無需根據瀏覽器、Worker線程和Node.js環境分別使用window、self和global,並支持對其它一些邊緣情況的處理。

新的export語法(export * as ns from “mod)提供了新的export from方式,支持將另一個模塊命名空間中的外來對像以命名的方式導出,提供類似於現有export from的使用方式。

Promise.allSettled()的提出,完善了ECMAScript ES2015現有的Promise.all()和Promise.race()方法。該方法無論各Promise的返回結果是滿足還是拒絕,都會執行設定的操作。示例代碼如下:

Promise.allSettled([
  fetch("https://api.github.com/users/pawelgrzybek").then(data => data.json()),
  fetch("https://api.github.com/users/danjordan").then(data => data.json())
])
  .then(result => console.log(`All profile settled`));

在上例中如果使用標準的Promise.all(),一旦第一個Promise被拒絕,那麼整個Promise操作都會被拒絕,這樣第二個Promise永遠無法得到滿足。 Promise.allSettled可處理需考慮部分執行結果的情況,例如一個Promise被拒絕,而另一個得到滿足。

“可選鏈”(Optional chaining,語法為“(a?.b)”)和“空位合併”(nullish coalescing,語法為“(a ?? b)”)已得到Babel(7.0及以上版本)、Edge/Chrome/Firefox等常用瀏覽器以及TypeScript 3.7以上版本的支持。兩個特性支持在訪問或調用值為空位的情況下執行短路操作。例如,let x = foo?.bar.baz()語句可替代:

let x = foo === null || foo === undefined ? undefined : foo.bar.baz();

BigInt支持開發人員精確操作大型數值。創建BigInt時,需在整型值後添加n,例如10n,或是通過調用BigInt()方法。例如,2 ** 53 + 1的求值結果為9007199254740992,但該值是一個奇數,不可能以2為結尾,所以產生了錯誤。如果定義為2n ** 53n +1n,那麼就可正確求值為9007199254740993n。這也是為什麼Twitter的JSON API以字符串而非整型數值形式返回推文ID值的原因。部分最新版本瀏覽器已支持BigInt,其中包括Firefox 68和Chrome 67以上版本,其它一些瀏覽器正在著力解決中

String.matchAll已得到除Safari外所有主要瀏覽器的支持。 matchAll()方法返回字符串匹配所有結果的迭代器,支持“捕獲組”(capturing groups)等正則表達式,示例代碼如下:

const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?d{4}).(?d{2}).(?d{2})/gu;
const results = Array.from(text.matchAll(regexp));

// results:
// [
//   [
//     '2019.01.29',
//     '2019',
//     '01',
//     '29',
//     index: 5,
//     input: 'From 2019.01.29 to 2019.01.30',
//     groups: { year: '2019', month: '01', day: '29' }
//   ],
//   [ (...) ]
// ]

TC39委員會由JavaScript開發人員、業界、學者等各方組成,與社區合作一併維護JavaScript(即先前的ECMAScript),並推進其發展。 TC39中包括了各主要瀏覽器廠商,每個ECMAScript特性提案將經歷如下五個成熟度階段,即階段0:“稻草人”(Strawman)階段;階段1:提議階段;階段2:草案階段;階段3:候選階段;階段4:完成階段。達成階段4的特性,將添加到標準中,並可安全使用。

ECMAScript語言規範的首個版本於1997年發布,ECMAScript 2020是該規範的第十一版。目前,ECMAScript是全球範圍內最廣為使用的通用編程語言。

原文鏈接:

ES2020’s Feature Set Finalized