1. 程式人生 > >2019 年的 JavaScript 新特性學習指南

2019 年的 JavaScript 新特性學習指南

昨天在瀏覽 Babel 網站時,看到它的 blog 有一篇新的文章,說 Babel 釋出了新的程式碼支援 class 的私有屬性和方法。

這著實讓我頭腦混亂,到底在哪可以瞭解到最新的規範?而這些規範又是否被支援?支援到什麼程度?完全沒有頭緒。

自從 ES6 規範釋出以來,帶來很多新的特性,而我們在消化這些大量的知識時,ES 規範也在不停的調整和增加內容。可是我們沒有一個特定的流程和渠道來獲取最新的資訊,這反而會越來越落後於前沿技術。

所以在2018年的年末我整理了一下學習 ES 特性的流程和過程中要接觸到的名詞。

什麼是 Ecma ?

在20世紀60隨著計算機的普及,不同製造商在使用各自的標準開發軟體,這使得為這些不同的裝置編寫語言更加困難。

為了統一計算機領域的部分標準,歐洲知名的計算機制造商們決定城裡一個協會來組建並制定章程和規則,這個協會就是「歐洲計算機制造協會」(European Computer Manufacturers Association) 簡稱「ECMA」

時間到了1994年,為了體現全球化的程序,該協會改名為「歐洲資訊和通訊系統標準化協會」(European association for standardizing information and communication systems) 簡稱 「Ecma International」,雖然名稱變化了,但是因為某些歷史原因「Ecma」的商標卻任然保留了下來沿用至今。

Ecma 的歷史

什麼是 TC39 ?

「TC39」全稱「Technical Committee 39」譯為「第39號技術委員會」,是 Ecma 組織架構中的一部分。是負責迭代和發展 ECMAScript 語言規範的委員會,它的成員由各個主流瀏覽器廠商的代表組成,通常每年召開約 6 次會議來討論未決提案的進展情況,會議的每一項決議必須得到大部分人的贊同,並且沒有人強烈反對才可以通過。

TC39 主要負責:

  1. 維護和更新 ECMAScript 程式語言的標準。
  2. 識別、開發、維護 ECMAScript 的擴充套件功能庫。
  3. 開發測試套件。
  4. 為 ISO/IEC JTC 1 提供標準。
  5. 評估和考慮新新增的技術方案。

TC39 - ECMAScript

TC39 - Royalty Free TG

TC39怎麼工作

ECMAScript 從 ES5 版本到 ES6 版本的釋出經歷了6年的時間,這帶來了兩個問題:

  1. 即使很早就完成的某項特性,也必須等到整個版本釋出才能釋出出來。
  2. 有些特性的定製會花費很多時間,那麼它在實現前都必須承受很大的壓力,因為沒有趕上本次釋出就必須再等很久,直至下一次釋出。

因此 TC39 改變了過去漫長的釋出流程,從 ECMAScript 2016 (ES7) 開始,每年釋出一個版本,這個版本會包含本年完成的所有功能。

那什麼功能算是完成,又有什麼功能可以加入議程中呢?

這就需要了解一下 TC39 的工作流程,TC39 會收集各種提案,這些提案來自 TC39 會員或註冊為 TC39 撰稿人的非會員。而提案會從 0 階段(stage 0)開始進入稽核流程,它們最終會演變為 ECMAScript 的標準,或者被廢棄。後面的章節中會詳細介紹。

什麼是 ECMAScript ?

ECMAScript 是一種計算機語言的規範,是 Ecma 組織的第 262 號規範(Ecma-262)。現在我們也用 ESx 來指代 ECMAScript x 版本(x 代表6、2016、2017等)。

Javascript 是 ECMAScript 的一個實現。之所以用這麼奇怪的方式來描述它,是因為任何人或組織都可以依照規範來實現語言。舉例來說,微軟也曾經按照 ECMAScript 標準開發出一門語言叫做 JScript,這門語言本用在 IE 瀏覽器中。

不過在普世語境下 Javascript 和 ECMAScript 兩個詞已經可互換使用了,而它們也確實有很深的羈絆。

1996年8月,微軟模仿 JavaScript 開發了一種相近的語言,取名為JScript(JavaScript 是 網景 的註冊商標,微軟不能用),首先內置於IE 3.0。網景公司面臨喪失瀏覽器指令碼語言的主導權的局面。網景公司決定將 JavaScript 提交給 Ecma,希望 JavaScript 能夠成為國際標準,以此抵抗微軟。

在提交給 Ecma 之所以不叫 JavaScript,一方面是由於商標的關係,Java 是 Sun 公司的商標,根據一份授權協議,只有網景公司可以合法地使用 JavaScript 這個名字,且 JavaScript 已經被網景公司註冊為商標,另一方面也是想體現這門語言的制定者是 Ecma,不是網景,這樣有利於保證這門語言的開放性和中立性。

ECMAScript® 2018 Language Specification

JavaScript 語言的歷史 - JavaScript 教程 - 網道

What is language and what is dialect for computers?

ECMAScript 版本怎麼命名?

1997年 Ecma 釋出 「ECMAScript Language Specification, Edition 1」簡稱「ES1」,隨後的每次釋出都會在原有版本上加1。

2009年 ES5正式釋出,而兩年後 ES5.1釋出。

又過了6年,一拖再拖的 ES6 才問世。

人們已經察覺到 Javascript 的發展速度要比其規範要快得多,一旦一個想法進入討論階段,瀏覽器就會嘗試為這個特性開發原型,而社群也會開始編碼實驗。所以有人建議未來的版本應該基於年份,比如用 ES2016 來標示在 2016 年結束之前敲定的任何特性規範。

儘管 ES6 被正式更名為 ES2015,但人們還是更多的習慣稱其為 ES6。不過從 ES6 以後的規範版本就正式使用年份的命名方式。

額外說一句,還沒有正式釋出的規範也就是還在定製階段的特性都被稱為 ESNext。

你不知道的JavaScript(下卷) -圖書-圖靈社群

What is ESNext? Is it same as ECMAScript? - Web, Design, Programming

ECMAScript 的規範更新流程是什麼?

之前說到 TC39 會收集各種提案,並讓這些提案進入稽核流程,一步步推進。整個流程有5個階段,每個階段都有一定的准入門檻和評定標準,我們也不需要關心這些標準條目,我們只需要知道一個提案到達的階段越靠後則它被納入規範的可能性就越大。

stage-0 - 稻草人(straw-man) 基本沒有準入門檻,合規的想法都可以進入這個階段。

stage-1 - 提案(proposal) 需要確定一個提案推進人。然後概括問題或需求並且形成一個解決方案,列舉新提案使用的方法或提供的API。討論關鍵演算法、概念和語義。

stage-2 - 草案(Draft) 這個階段需要使用正式的規範語言精確地描述語法和語義

stage-3 - 候選方案(Candidate) 當草案進入這個階段就需要進一步細化並接收使用者的反饋,並描述完所有語義、語法和 API。

stage-4 - 結束(Finished) 當進入這個階段時,提案會接受測試和驗收,通過後就會進入下一個版本 ES 規範的標準之中。

每年7月份,TC39 會正式釋出當年的 ES 規範。

The TC39 Process

The TC39 process for ECMAScript features

在哪追蹤 ES6 以後的規範變化?

很高興 ECMAScript 擁抱了 GitHub 社群,通過社群本身的力量來發展自身並回饋於社群。

TC39 on GitHub

TC39 擁有很多倉庫:

  • ecma262 倉庫主要維護 ECMAScript 規範文件。
  • proposals 倉庫主要維護提案的列表及進度。
  • 還有很多測試套件和其他一些規範。

所以迴歸到章節的問題上來,我們要追蹤 ES6 以後的規範變化就需要在 proposals 倉庫裡找答案。這個倉庫包含了 4 大部分,分別是 「stage-0 的提案列表」「stage-1 到 3 的提案列表」「結束(stage-4)的提案列表」「非活躍(inactive)的提案列表」

我們在 結束的提案列表裡 能找到所有 ES6 以後新增的特性,下面就列出這些特性以及釋出的規範版本: ES2016: * Array.prototype.includes * 冪操作符 ES2017 * Object.values / Object.entries * 字串填補 * Object.getOwnPropertyDescriptors * 容許函式引數尾後逗號 * Async 函式 * 記憶體分享和原子操作 ES2018 * 正則表示式 s 標誌 * 正則表示式中組的命名 * 物件屬性的解構賦值 * 正則表示式反向斷言 * 正則表示式 Unicode 屬性轉義 * Promise.prototype.finally * 非同步迭代器

在 結束的提案列表裡 還包含了一些計劃在 2019 年釋出的特性,由於其還未正式釋出我將其歸納在 ESNext 中就不在此列出了。

Release ES2016 Draft 1 · tc39/ecma262 · GitHub

proposals/finished-proposals.md · tc39/proposals · GitHub

ES 標準與瀏覽器實現差異

特性的演變迅速也讓 JavaScript 開發者遇到了問題,新的特性可以使得編寫出更高效健壯的程式碼,但我們我們的網站卻要支援未提供這些新特性的舊版瀏覽器。在功能特性快速進化的環境下這個問題更加嚴峻。

上圖中綠色的部分就是 ECMAScript 特性和瀏覽器支援的特性的差異部分,這個差異可以分成兩大部分:新的 API新的語法

新的 API 是在原有物件的拓展,比如 Array.includes 就是對陣列物件的拓展。它通常是解決一些歷史遺留問題或者對常用程式碼邏輯的封裝。

舉例來說,Object.is() 是一個用於檢查兩個值是否嚴格相等的新介面。=== 在處理 NaN-0 這樣的值時會有微妙的歧義,而 Object.is() 就是用來解決這樣問題的。

NaN === NaN; // false
Object.is(NaN, NaN) // true
複製程式碼

對於 API 的擴充套件帶來的規範特性和瀏覽器特性的差異,通常都有一個被稱為 polyfill 或者 shim 的模式來抹平。這兩個詞的意思分別是 膩子 和 墊片,從詞義上來說已經能很形象的描述它們的作用。

而 polyfill 可以使用 ES5 的程式碼來實現這些新 API,就以 Object.is() 來說就可以用以下程式碼來實現:

if (!Object.is) {
  Object.is = function(x, y) {
    // SameValue algorithm
    if (x === y) { // Steps 1-5, 7-10
      // Steps 6.b-6.e: +0 != -0
      return x !== 0 || 1 / x === 1 / y;
    } else {
      // Step 6.a: NaN == NaN
      return x !== x && y !== y;
    }
  };
}
複製程式碼

新的語法就比如 let ,是對功能的擴充套件。想要在舊瀏覽器中使用不支援的語法就必須要使用「轉換+編譯」的技術,利用專門的工具把程式碼轉化為等價(或近似)的可以在 ES5 環境下工作的程式碼。

你不知道的JavaScript(下卷) -圖書-圖靈社群

ECMAScript Shims · GitHub

在哪裡檢視 ECMAScript 特性在執行環境中的相容性?

這裡提供一個網站,專門檢視相容性表格。包含瀏覽器、手機端和伺服器端。

ECMAScript 6 compatibility table

什麼是 Babel?

Babel 是一個 JavaScript 編譯工具,專門用來編譯 ECMAScript 6+ 的程式碼讓其相容就瀏覽器或執行環境。它可以轉換語法、補充 API。

在聖經故事裡,Babel 譯為「巴別塔」,當時世界只講同一種語言,人類決定修建一座能夠通天的高塔來傳播自己的名聲。上帝知道了此事,擔心人類過於強大,就打亂了人類的語言,讓人類不講同語不齊同心。於是人類便分裂開來,這座塔也不再建造了。

而這個編譯器借用 Babel 之名,似乎是想幫助人類統一 Javascript 語言呢(笑。

鑑於它在社群的普及程度很高所以本文不會介紹其具體的使用方式,而是介紹它如何配合 TC39 的工作流程。

如今的 Babel 已經發展到第7個大版本,它提供的子功能的責任劃分也越來越清晰,對於開發者來說需要關心兩個方面:

  • 把程式碼編譯到什麼程度?
  • Babel 對新 ES 特性的支援程度是多少?

通常把程式碼編譯到 ES5 的版本是最安全的,這個版本已經得到絕大多數瀏覽器的支援,但這會讓編譯後的程式碼檔案更大。但我們總不能在2030年還這樣做,隨著舊瀏覽器逐漸被淘汰,我們也不需要把所有的特性都編譯至 ES5 的版本。

Babel 本次更新的第7個版本,引入了 @babel/preset-env 來動態管理編譯程度。如果進入這個包而不做任何配置,則會預設把程式碼編譯到 ES5 版本。

重要的是這次 @babel/preset-env 僅包含了對已正式釋出的 ES 規範的支援。如果要使用任一 stage-0 到 stage-3 中的特性或者 stage-4 中存在但是當年還未正式釋出的特性,就必須安裝相應的外掛。

如果新特性以API的方式實現,就需要在polyfill中檢視,polyfill中包含一個core-js列表專門包含了這些API。

巴別塔 - 維基百科,自由的百科全書

@babel/preset-env · Babel

@babel/Plugins · Babel

GitHub - zloirock/core-js: Standard Library

怎麼搭配 TC39 和 Babel 來使用最新特性?

這就是本文的最終總結了,怎樣嘗試使用一個新的特性。

如果你在別人的程式碼裡或者網路上發現一個你沒見過的 JS 程式碼語法你應該怎麼辦呢?

首先你應該嘗試通過搜尋引擎找到這種語法的正式名稱。然後你就可以去 TC39 的 github 中找一下,你可以在 ecma-262 正式文件中找(不過這個文件太長了)也可以在 proposals 列表裡找一下,別遺漏了 finished proposals 和 inactive proposales 列表,最終你就會找到這個語法的介紹和用例。

接著你會想看一下這個語法在不同環境下的支援程度,所以你需要開啟相容性表格查詢頁面查詢這個語法。

接著你也許會想嘗試著編寫一個用例並執行一下,那你需要在 Babel 的官網裡查一下 plugins 列表裡是否支援該語法,如果是新的 API 那就需要在 core-js 列表裡找一下。

接著你就可以配置好 Babel 並編寫用例,編譯成瀏覽器相容的程式碼,在瀏覽器裡運行了。

學習 JS 參考頁面總集

TC39 on GitHub - TC39 的 GitHub 帳號

ECMAScript® Language Specification - ECMAScript 最新修訂版(當年準備釋出的文件)

ECMAScript® Language Specification - ECMAScript 最新正式版(已釋出的最新文件)

proposals - 提案列表

ECMAScript 6 compatibility table - 相容性表格查詢頁面

@babel/Plugins · Babel - Babel 支援的語法外掛列表

GitHub - zloirock/core-js - Babel polyfill 中支援的 API 列表

Exploring JS - 線上學習 JS 的網站作者挺牛的

ES.next News - ES 新聞訂閱

寫於2019年1月。