原文做者:Faraz Kelhinijavascript
譯者:UC 國際研發 Jothycss
寫在最前:歡迎你來到「UC國際技術」公衆號,咱們將爲你們提供與客戶端、服務端、算法、測試、數據、前端等相關的高質量技術文章,不限於原創與翻譯。前端
編者按:曾幾什麼時候,年少的我捧着阮一峯老師的《ES6 標準入門》,感嘆 JS 變遷實在太快,好怕學不動了。直至寫了幾年 ES6 的今日,回頭看方知:不要爲了學 ES X 而學 ES X,不管 ES 幾其實都是語法糖,是輔助角色,重點是想清楚它能爲咱們的開發帶來什麼好處,而不是本末倒置。今天介紹的 ES2018 新特性仍是有蠻多亮點的,一塊兒來看看吧。java
ECMAScript 標準的第九版,官宣爲 ECMAScript 2018(或簡稱 ES2018),已於 2018 年 6 月發佈。從 ES2016 開始,每隔一年就會發布一版 ECMAScript 規範的新版本,並添加很少於主版本的功能。 最新的這個版本延續了每一年發佈的週期,新增了四個新的 RegExp
特性,rest/spread 屬性,異步迭代和 Promise.prototype.finally
。 此外,它還從標記模板中刪除了轉義序列的語法限制。
git
咱們將在後面的小節中詳細解釋這些新變化 😉。程序員
回顧 ES2015,最有趣的功能當數 spread 運算符。 該運算符極大簡化了數組的複製及合併。你可使用它替換concat()
或slice()
方法:github
在必須將數組的各個項分別做爲參數傳入函數的狀況下,擴展運算符也派得上用場。 例如:正則表達式
經過向對象文法添加 spread 屬性,ES2018 進一步擴展了此語法。 使用 spread 屬性,你能夠將對象自身的可枚舉屬性複製到新對象上。舉個例子 🌰:算法
在此代碼中,...
運算符用於檢索 obj1 的屬性並將它們分配給 obj2。 在 ES2018 以前,這麼作會報錯的。 若是出現多個屬性同名的狀況,將會取最後一個值:編程
Spread 屬性還提供了一種合併兩個或多個對象的新方法,能夠替代 Object.assign()
方法使用:
在此代碼中,Object.assign()
方法會執行其繼承的 setter 屬性,而 spread 屬性則徹底忽略了這一步。
切記!spread 屬性只複製可枚舉屬性。 在下面的例子中,type
屬性不會出如今複製出的對象中,由於其enumerable
屬性爲 false
:
繼承屬性即便是可枚舉的,也會被忽略:
在這段代碼中,car2
繼承了car
的color
屬性。 因爲 spread 僅複製對象自身的屬性,所以返回值中不包含 color
屬性。
請記住,spread 只是對象的淺複製。 若是屬性中包含對象,則僅複製對象的引用:
copy1
中的 x
屬性與copy2
中的x
屬性引用了內存中同一個對象,所以嚴格等於(strict equality)運算符返回 true.
ES2015 新增的另外一有用功能是 rest 參數,它使 JavaScript程序員可以使用...
將值表示爲數組。 例如:
arr
的第一項被賦值給 x,剩下的被賦值給 rest
變量。 這種名爲數組解構的模式很是受歡迎,以致於 Ecma 技術委員會(Ecma Technical Committee)決定爲對象帶來相似的功能:
此代碼使用 rest 屬性解構賦值,將對象 obj
剩餘的自身可枚舉屬性複製到新對象rest
中。 須要引發注意的是,rest 屬性必須始終位於對象的末尾,不然會報錯:
此外,在對象中使用多個 rest 語法也會報錯,除非它們是嵌套使用的:
8.0.0(須要 --harmony 運行時 flag)
8.3.0(徹底支持)
迭代數據集是編程的重要組成部分。 在 ES2015 以前,JavaScript提供了for
,for...in
和 while
等語句,以及map()
,filter()
和 forEach()
等方法。 爲了方便程序員一個個地處理集合元素,ES2015 引入了迭代器接口。
若是對象具備 Symbol.iterator
屬性,則表示它是可迭代的。 在 ES2015 中,字符串和集合對象(如Set
, Map
和 Array
)帶有Symbol.iterator
屬性,所以是可迭代的。 如下代碼說明了如何每次訪問一個可迭代元素☝️:
Symbol.iterator
是個廣爲人知的符號,用於表示返回迭代器的函數。與迭代器交互主要使用next()
方法。此方法返回一個具備value
和done
兩個屬性的對象。 value
屬性包含集合中下一個元素的值。done
屬性包含true
或false
,代表是否已到達集合的末尾。
默認狀況下普通對象不可迭代,但若是在其上定義了 Symbol.iterator
屬性,則它可變爲可迭代對象,以下所示:
collection
對象是可迭代的,由於它定義了 Symbol.iterator
屬性。 iterator 使用 Object.keys()
方法獲取對象屬性名的數組,而後將其賦值給常量values
.它還定義了一個計數器變量i
,初始值爲 0. 當執行迭代器時,它返回一個包含 next()
方法的對象。 每次調用 next()
方法時,它都返回一個 {value, done}
鍵值對,其中 value
保存集合中的下一個元素,done
保存一個布爾值,表示迭代器是否已達到集合的末尾。
雖然以上代碼運行完美,但它本無需如此複雜。 所幸,生成器( generator )函數能夠大大簡化該過程:
在今生成器中,for...in
循環用於枚舉集合,yield 每一個屬性的值。 結果與前一個示例徹底相同,但代碼量大大減小。
迭代器的缺點是它們不適合表示異步數據源。 ES2018 的補救方案是異步迭代器(asynchronous iterators)和異步可迭代對象(asynchronous iterables)。 異步迭代器與傳統迭代器的不一樣點在於,它不返回 {value,done}
的形式的普通對象,而是返回一個完成(fulfill) {value,done}
的promise
.異步可迭代對象定義了一個返回異步迭代器的 Symbol.asyncIterator
方法(注意不是 Symbol.iterator
)。
舉個例子🌰可能更清楚些:
請注意,使用 promises 的迭代器不可能達到相同的結果。 雖然普通的同步迭代器能夠異步產生肯定值,但它仍然須要同步肯定「完成(done)」的狀態。
一樣,你可使用生成器函數簡化此過程,以下所示:
一般生成器函數會返回帶有next()
方法的生成器對象。 當調用 next()
時,它返回一個 {value,done}
鍵值對,其 value
屬性保存了yield 的值。 異步生成器與之相似,只不過它返回的是一個完成了 {value,done}
的promise.
使用 for...of
語句能夠輕鬆迭代可迭代對象,可是 for...of
不能與異步可迭代對象一塊兒使用,由於 value
和 done
不是同步產生的。 出於這個緣由,ES2018 提供了 for...await...of
語句。 咱們來看一個例子:
在此代碼中, 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
語句,以下所示:
8.10.0(須要 --harmony_async_iteration flag)
10.0.0(徹底支持)
ES2018另外一振奮人心的特效是finally()
方法。 以前有幾個 JavaScript 庫實現了相似的方法,而且它被證明是有用的。這促使 Ecma技術委員會正式將finally()
添加到規範中。 使用該方法,開發者可無需理會 promise 命數如何,直接執行這個代碼塊中的代碼。 咱們來看一個簡單的例子:
finally()
方法可在操做完成後進行一些掃尾(clean up)工做,不管操做是否成功。 在此代碼中,finally()
方法在數據獲取處理後直接隱藏了加載 spinner。 不管 promise 完成與否,函數中的註冊代碼都會執行,開發者沒必要在 then()
和 catch()
方法中重複編寫邏輯。
使用promise.then(func, func)
也可實現與promise.then(func, func)
一樣的效果,但你必須在 fulfillment 句柄及 rejection 句柄中重複相同的代碼,或者引入一個變量:
與 then()
和 catch()
相同,finally()
方法老是返回一個 promise,所以你能夠連接更多的方法。 通常來講,咱們會將 finally()
做爲最後一環。但某些狀況,例如在建立 HTTP 請求時,在 finally()
以後連接另外一個catch()
,以處理請求中可能發生的錯誤是不錯的實踐。
Node.js:
10.0.0(徹底支持)
ES2018 爲 RegExp
對象增長了四個新特性,進一步提升了 JavaScript 的字符串處理能力。 這些特性以下:
s(dotAll)標誌
可命名捕獲組
Lookbehind斷言
Unicode 屬性轉義
點(.)是正則表達式模式中的特殊字符,它匹配除換行符以外的任何字符,例如換行符(\n
)或回車符(\r
)。要匹配包括換行符在內的全部字符,解決方法是使用兩個相反短字的字符類,例如[\d\D]
. 此字符類告訴正則表達式引擎找到一個數字(\d
)或非數字(\D
)的字符。 所以,它匹配任意字符:
ES2018 引入了一種模式,其中點可用於實現相同的結果。可使用s
標誌在每一個正則表達式的基礎上激活此模式:
利用標誌來選擇性使用新特性的好處是向後兼容,保證使用點字符的現有正則表達式模式不受影響。
在一些正則表達式模式中,使用數字來引用捕獲組可能會形成混淆。 例如,採用正則表達式 /(\d{4})-(\d{2})-(\d{2})/
匹配日期。 因爲美式英語中的日期符號與英式英語不一樣,所以很難知道哪一個組指的是日,哪一個組指的是月:
ES2018 引入了使用(?<name>...)
語法的命名捕獲組。 所以,匹配日期的模式能夠用不太模糊的方式編寫:
你可使用 \k<name>
語法在模式中再次調用命名捕獲組。 例如,要查找句子中連續的重複單詞,可使用 /\b(?<dup>\w+)\s+\k<dup>\b/
:
要將命名捕獲組用於 replace()
方法的替換字符串,你可使用 $<name>
構造。 例如:
ES2018 爲 JavaScript 帶來了後行斷言(lookbehind assertion),該斷言已在其餘語言的正則表達式使用多年。 之前,JavaScript 只支持先行斷言(lookahead assertion)。 後行斷言用 (?<=...)
表示,使你可以根據模式以前的子字符串匹配模式。 例如,若是你想要在不捕獲貨幣符號的狀況下以美圓,英鎊或歐元匹配產品的價格,你可使用/(?<=\$|£|€)\d+(\.\d*)?/
:
還有一個負向的後行斷言,用 (?<!...)
表示。 負向後行斷言容許你匹配不跟在某後行斷言以後的模式(譯者注:差點把我本身都繞暈了😷 舉個簡單的例子(?<!a)b
: 斷言 b 前面沒有 a,匹配 bb 但不匹配 ab,最終捕獲 b)。 例如,模式 /(?<!un)available/
可在無 「un」 前綴的狀況下匹配 available:
ES2018 提供了一種稱爲 Unicode 屬性轉義的新轉義序列類型,它在正則表達式中提供對完整 Unicode 的支持。 假設你要匹配字符串中的 Unicode 字符 ㉛. 雖然咱們認爲 ㉛ 是一個數字,可是咱們不能用 \d
匹配它,由於它只支持 ASCII [0-9] 字符。此外,Unicode 屬性轉義也可用於匹配 Unicode 中的任何十進制數:
一樣,若是要匹配任意 Unicode 單詞(劃掉)字母字符,可使用 \p{Alphabetic}
:
還有一個否認版本的\p{...}
,用\P{...}
,表示:
除了字母和數字以外,還有幾個屬性能夠在 Unicode 屬性轉義中使用。 你能夠在當前規範提案中找到支持的 Unicode 屬性列表。
地址:https://tc39.github.io/proposal-regexp-unicode-property-escapes/#sec-static-semantics-unicodematchproperty-p
8.3.0(須要 --harmony 運行時 flag)
8.10.0(支持 s(dotAll) 標誌和後行斷言)
10.0.0(徹底支持)
當模板字符串緊跟在表達式以後時,它會被稱爲標記模板字符串。 當你想要使用函數解析模板字符串時,標記模板會派上用場。 看看這個例子:
上面的代碼調用了標記表達式(它是常規函數)並傳遞模板字符串。 該函數只是修改字符串的動態部分並返回它。
在 ES2018 以前,標記的模板字符串具備與轉義序列相關的語法限制。 反斜槓後跟某些字符序列被視爲特殊字符:\x
被解析爲十六進制轉義符,\u
被解析爲unicode轉義符,\_
後跟一個數字被解析爲八進制轉義符。 所以,解釋器將諸如 "C:\xxx\uuu"
或 "\ubuntu"
之類的字符串視爲無效的轉義序列,並將拋出SyntaxError
.
ES2018 從標記模板中刪除了這些限制,它會將無效轉義序列表示爲 undefined
,而不是拋出錯誤:
請記住,在常規模板字符串中使用非法轉義序列仍會報錯:
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/
好文推薦:
「UC國際技術」致力於與你共享高質量的技術文章
歡迎關注咱們的公衆號、將文章分享給你的好友