每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Jothy發表於2019-01-21

原文作者:Faraz Kelhini

譯者:UC 國際研發 Jothy


寫在最前:歡迎你來到“UC國際技術”公眾號,我們將為大家提供與客戶端、服務端、演算法、測試、資料、前端等相關的高質量技術文章,不限於原創與翻譯。

編者按:曾幾何時,年少的我捧著阮一峰老師的《ES6 標準入門》,感嘆 JS 變遷實在太快,好怕學不動了。直至寫了幾年 ES6 的今日,回頭看方知:不要為了學 ES X 而學 ES X,無論 ES 幾其實都是語法糖,是輔助角色,重點是想清楚它能為我們的開發帶來什麼好處,而不是本末倒置。今天介紹的 ES2018 新特性還是有蠻多亮點的,一起來看看吧。


ECMAScript 標準的第九版,官宣為 ECMAScript 2018(或簡稱 ES2018),已於 2018 年 6 月釋出。從 ES2016 開始,每隔一年就會發布一版 ECMAScript 規範的新版本,並新增不多於主版本的功能。 最新的這個版本延續了每年釋出的週期,新增了四個新的 RegExp 特性,rest/spread 屬性,非同步迭代和 Promise.prototype.finally。 此外,它還從標記模板中刪除了轉義序列的語法限制。

我們將在後面的小節中詳細解釋這些新變化 ?。



rest/spread 屬性

回顧 ES2015,最有趣的功能當數 spread 運算子。 該運算子極大簡化了陣列的複製及合併。你可以使用它替換concat()slice()方法:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性


在必須將陣列的各個項分別作為引數傳入函式的情況下,擴充套件運算子也派得上用場。 例如:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性


通過向物件文法新增 spread 屬性,ES2018 進一步擴充套件了此語法。 使用 spread 屬性,你可以將物件自身的可列舉屬性複製到新物件上。舉個例子 ?:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

在此程式碼中,... 運算子用於檢索 obj1 的屬性並將它們分配給 obj2。 在 ES2018 之前,這麼做會報錯的。 如果出現多個屬性同名的情況,將會取最後一個值:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性


Spread 屬性還提供了一種合併兩個或多個物件的新方法,可以替代 Object.assign() 方法使用:每個 JavaScript 開發者都該瞭解的 ES2018 新特性

在此程式碼中,Object.assign() 方法會執行其繼承的 setter 屬性,而 spread 屬性則完全忽略了這一步。

切記!spread 屬性只複製可列舉屬性。 在下面的例子中,type 屬性不會出現在複製出的物件中,因為其enumerable 屬性為 false

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

繼承屬性即使是可列舉的,也會被忽略:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

在這段程式碼中,car2 繼承了carcolor 屬性。 由於 spread 僅複製物件自身的屬性,因此返回值中不包含 color 屬性。

請記住,spread 只是物件的淺複製。 如果屬性中包含物件,則僅複製物件的引用:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

copy1 中的 x 屬性與copy2中的x 屬性引用了記憶體中同一個物件,因此嚴格等於(strict equality)運算子返回 true.

ES2015 新增的另一有用功能是 rest 引數,它使 JavaScript程式設計師能夠使用...將值表示為陣列。 例如:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

arr 的第一項被賦值給 x,剩下的被賦值給 rest 變數。 這種名為陣列解構的模式非常受歡迎,以至於 Ecma 技術委員會(Ecma Technical Committee)決定為物件帶來類似的功能:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

此程式碼使用 rest 屬性解構賦值,將物件 obj 剩餘的自身可列舉屬性複製到新物件rest中。 需要引起注意的是,rest 屬性必須始終位於物件的末尾,否則會報錯:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

此外,在物件中使用多個 rest 語法也會報錯,除非它們是巢狀使用的:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性


Rest/Spread 屬性支援

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Node.js:
  • 8.0.0(需要 --harmony 執行時 flag)

  • 8.3.0(完全支援)


非同步迭代

迭代資料集是程式設計的重要組成部分。 在 ES2015 之前,JavaScript提供了for,for...inwhile 等語句,以及map(),filter()forEach() 等方法。 為了方便程式設計師一個個地處理集合元素,ES2015 引入了迭代器介面。

如果物件具有 Symbol.iterator 屬性,則表示它是可迭代的。 在 ES2015 中,字串和集合物件(如Set, MapArray)帶有Symbol.iterator 屬性,因此是可迭代的。 以下程式碼說明了如何每次訪問一個可迭代元素☝️:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Symbol.iterator 是個廣為人知的符號,用於表示返回迭代器的函式。與迭代器互動主要使用next()方法。此方法返回一個具有valuedone 兩個屬性的物件。 value 屬性包含集合中下一個元素的值。done 屬性包含truefalse,表明是否已到達集合的末尾。

預設情況下普通物件不可迭代,但如果在其上定義了 Symbol.iterator 屬性,則它可變為可迭代物件,如下所示:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

collection 物件是可迭代的,因為它定義了 Symbol.iterator 屬性。 iterator 使用 Object.keys() 方法獲取物件屬性名的陣列,然後將其賦值給常量values.它還定義了一個計數器變數i,初始值為 0. 當執行迭代器時,它返回一個包含 next() 方法的物件。 每次呼叫 next() 方法時,它都返回一個 {value, done} 鍵值對,其中 value 儲存集合中的下一個元素,done 儲存一個布林值,表示迭代器是否已達到集合的末尾。

雖然以上程式碼執行完美,但它本無需如此複雜。 所幸,生成器( generator )函式可以大大簡化該過程:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

在此生成器中,for...in 迴圈用於列舉集合,yield 每個屬性的值。 結果與前一個示例完全相同,但程式碼量大大減少。

迭代器的缺點是它們不適合表示非同步資料來源。 ES2018 的補救方案是非同步迭代器(asynchronous iterators)和非同步可迭代物件(asynchronous iterables)。 非同步迭代器與傳統迭代器的不同點在於,它不返回 {value,done} 的形式的普通物件,而是返回一個完成(fulfill) {value,done}promise.非同步可迭代物件定義了一個返回非同步迭代器的 Symbol.asyncIterator 方法(注意不是 Symbol.iterator)。

舉個例子?可能更清楚些:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

請注意,使用 promises 的迭代器不可能達到相同的結果。 雖然普通的同步迭代器可以非同步產生確定值,但它仍然需要同步確定“完成(done)”的狀態。


同樣,你可以使用生成器函式簡化此過程,如下所示:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

通常生成器函式會返回帶有next()方法的生成器物件。 當呼叫 next() 時,它返回一個 {value,done} 鍵值對,其 value 屬性儲存了yield 的值。 非同步生成器與之類似,只不過它返回的是一個完成了 {value,done} 的promise.

使用 for...of 語句可以輕鬆迭代可迭代物件,但是 for...of 不能與非同步可迭代物件一起使用,因為 valuedone 不是同步產生的。 出於這個原因,ES2018 提供了 for...await...of 語句。 我們來看一個例子:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

在此程式碼中, for...await...of 語句隱式呼叫集合物件上的Symbol.asyncIterator方法以獲取非同步迭代器。 每次迴圈時,都會呼叫迭代器的 next() 方法,該方法返回一個 promise. 一旦 promise 完成,就會將結果物件的 value 屬性讀取到x變數。 迴圈繼續,直到返回物件的 done 屬性值為true.

敲黑板!for...await...of 語句僅在非同步生成器和非同步函式中有效。 違反此規則會報 SyntaxError(語法錯誤)。


next() 方法可能會返回 rejected promise. 為了優雅地處理被 reject 的 promise,你可以使用try...catch語句包裹for...await...of 語句,如下所示:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

非同步迭代器支援

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Node.js:

  • 8.10.0(需要 --harmony_async_iteration flag)

  • 10.0.0(完全支援)


Promise.prototype.finally

ES2018另一振奮人心的特效是finally()方法。 之前有幾個 JavaScript 庫實現了類似的方法,並且它被證實是有用的。這促使 Ecma技術委員會正式將finally()新增到規範中。 使用該方法,開發者可無需理會 promise 命數如何,直接執行這個程式碼塊中的程式碼。 我們來看一個簡單的例子:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

finally() 方法可在操作完成後進行一些掃尾(clean up)工作,無論操作是否成功。 在此程式碼中,finally() 方法在資料獲取處理後直接隱藏了載入 spinner。 無論 promise 完成與否,函式中的註冊程式碼都會執行,開發者不必在 then()catch() 方法中重複編寫邏輯。

使用promise.then(func, func)也可實現與promise.then(func, func) 同樣的效果,但你必須在 fulfillment 控制程式碼及 rejection 控制程式碼中重複相同的程式碼,或者引入一個變數:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性


then()catch() 相同,finally() 方法總是返回一個 promise,因此你可以連結更多的方法。 一般來說,我們會將 finally() 作為最後一環。但某些情況,例如在建立 HTTP 請求時,在 finally() 之後連結另一個catch(),以處理請求中可能發生的錯誤是不錯的實踐。

Promise.prototype.finally 支援

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Node.js:

10.0.0(完全支援)


RegExp 新特性

ES2018 為 RegExp 物件增加了四個新特性,進一步提高了 JavaScript 的字串處理能力。 這些特性如下:

  • s(dotAll)標誌

  • 可命名捕獲組

  • Lookbehind斷言

  • Unicode 屬性轉義

s (dotAll) Flag

點(.)是正規表示式模式中的特殊字元,它匹配除換行符之外的任何字元,例如換行符(\n)或回車符(\r)。要匹配包括換行符在內的所有字元,解決方法是使用兩個相反短字的字元類,例如[\d\D]. 此字元類告訴正規表示式引擎找到一個數字(\d)或非數字(\D)的字元。 因此,它匹配任意字元:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

ES2018 引入了一種模式,其中點可用於實現相同的結果。可以使用s標誌在每個正規表示式的基礎上啟用此模式:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

利用標誌來選擇性使用新特性的好處是向後相容,保證使用點字元的現有正規表示式模式不受影響。

可命名捕獲組

在一些正規表示式模式中,使用數字來引用捕獲組可能會造成混淆。 例如,採用正規表示式 /(\d{4})-(\d{2})-(\d{2})/ 匹配日期。 由於美式英語中的日期符號與英式英語不同,因此很難知道哪個組指的是日,哪個組指的是月:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

ES2018 引入了使用(?<name>...)語法的命名捕獲組。 因此,匹配日期的模式可以用不太模糊的方式編寫:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

你可以使用 \k<name> 語法在模式中再次呼叫命名捕獲組。 例如,要查詢句子中連續的重複單詞,可以使用 /\b(?<dup>\w+)\s+\k<dup>\b/:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

要將命名捕獲組用於 replace() 方法的替換字串,你可以使用 $<name> 構造。 例如:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

後行斷言

ES2018 為 JavaScript 帶來了後行斷言(lookbehind assertion),該斷言已在其他語言的正規表示式使用多年。 以前,JavaScript 只支援先行斷言(lookahead assertion)。 後行斷言用 (?<=...) 表示,使你能夠根據模式之前的子字串匹配模式。 例如,如果你想要在不捕獲貨幣符號的情況下以美元,英鎊或歐元匹配產品的價格,你可以使用/(?<=\$|£|€)\d+(\.\d*)?/:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

還有一個負向的後行斷言,用 (?<!...) 表示。 負向後行斷言允許你匹配不跟在某後行斷言之後的模式(譯者注:差點把我自己都繞暈了? 舉個簡單的例子(?<!a)b: 斷言 b 前面沒有 a,匹配 bb 但不匹配 ab,最終捕獲 b)。 例如,模式 /(?<!un)available/ 可在無 “un” 字首的情況下匹配 available:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Unicode 屬性轉義

ES2018 提供了一種稱為 Unicode 屬性轉義的新轉義序列型別,它在正規表示式中提供對完整 Unicode 的支援。 假設你要匹配字串中的 Unicode 字元 ㉛. 雖然我們認為 ㉛ 是一個數字,但是我們不能用 \d 匹配它,因為它只支援 ASCII [0-9] 字元。此外,Unicode 屬性轉義也可用於匹配 Unicode 中的任何十進位制數:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

同樣,如果要匹配任意 Unicode 單詞(劃掉)字母字元,可以使用 \p{Alphabetic}:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

還有一個否定版本的\p{...},用\P{...},表示:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

除了字母和數字之外,還有幾個屬性可以在 Unicode 屬性轉義中使用。 你可以在當前規範提案中找到支援的 Unicode 屬性列表。

地址:https://tc39.github.io/proposal-regexp-unicode-property-escapes/#sec-static-semantics-unicodematchproperty-p

RegExp 新特性支援

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Node.js:

  • 8.3.0(需要 --harmony 執行時 flag)

  • 8.10.0(支援 s(dotAll) 標誌和後行斷言)

  • 10.0.0(完全支援)


模板字串修訂

當模板字串緊跟在表示式之後時,它會被稱為標記模板字串。 當你想要使用函式解析模板字串時,標記模板會派上用場。 看看這個例子:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

上面的程式碼呼叫了標記表示式(它是常規函式)並傳遞模板字串。 該函式只是修改字串的動態部分並返回它。

在 ES2018 之前,標記的模板字串具有與轉義序列相關的語法限制。 反斜槓後跟某些字元序列被視為特殊字元:\x 被解析為十六進位制轉義符,\u 被解析為unicode轉義符,\_ 後跟一個數字被解析為八進位制轉義符。 因此,直譯器將諸如 "C:\xxx\uuu""\ubuntu" 之類的字串視為無效的轉義序列,並將丟擲SyntaxError.

ES2018 從標記模板中刪除了這些限制,它會將無效轉義序列表示為 undefined,而不是丟擲錯誤:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

請記住,在常規模板字串中使用非法轉義序列仍會報錯:

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

模板字串修訂支援

每個 JavaScript 開發者都該瞭解的 ES2018 新特性

Node.js:

  • 8.3.0 (需要 --harmony 執行時 flag)

  • 8.10.0(完全支援)


總結

我們已經仔細研究了 ES2018 中引入的幾個關鍵特性,包括非同步迭代,rest/spread 屬性,Promise.prototype.finally以及 RegExp物件的新增特性。 雖然有些瀏覽器廠商尚未完全實現其中一些功能,但由於有 Babel 這樣的 JavaScript 轉換器,我們仍可以在今天使用它們。

ECMAScript 正在迅速發展,並且每隔一段時間就會引入新功能,歡迎檢視完整提案列表?,瞭解全部新功能。 有啥功能讓你特別興奮嗎?快快和我分享叭~

提案地址:https://github.com/tc39/proposals/blob/master/finished-proposals.md


原文地址:https://css-tricks.com/new-es2018-features-every-javascript-developer-should-know/


好文推薦:

一起來燃燒 Bundle 的“卡路里”



“UC國際技術”致力於與你共享高質量的技術文章

歡迎關注我們的公眾號、將文章分享給你的好友

每個 JavaScript 開發者都該瞭解的 ES2018 新特性



相關文章