詳解 ES 2018 新特性
英文:Faraz Kelhini 譯文:展翅肥羊
https://www.zcfy.cc/article/new-es2018-features-every-javascript-developer-should-know
前言
以下將逐一解釋這些變動:
一、Rest/Spread 特性
ES2015中添加的最有趣的特性之一是spread操作符。你可以用它替換concat()和slice()方法,使數組的操作(複製、合併)更加簡單。
在數組必須以拆解的方式作為函數參數的情況下,spread操作符也很有用。例如:
ES2018通過向對象文本添加擴展屬性進一步擴展了這種語法。他可以將一個對象的屬性拷貝到另一個對象上,參考以下情形:
在上述代碼中,spread操作符遍歷obj1屬性,並將其添加到obj2的屬性中;而在之前的版本中,如此處理會拋出一個異常。需要注意的是,如果存在相同的屬性名,只有最後一個會生效。
同時,Spread操作符可以作為Object.assign() 的一個替代方案進行對象融合:
然而,在進行對象融合時,Spread操作結果並不總是與Object.assign()一致,例如:
在上述代碼中,Object.assign()方法繼承了setter屬性;而spread操作忽略了setter。
劃重點:spread只複製枚舉屬性。在下面的例子中,type屬性不會出現在複製對象中,因為它的枚舉屬性被設置為false:
繼承的屬性即使是可枚舉的也會被忽略:
在上述代碼中,car2繼承了car中的color屬性。因為spread操作只會複製對象自身的屬性,color並沒有出現在新的對象中。
spread只會進行淺拷貝,如果屬性的值是一個對象的話,只有對象的引用會被拷貝:
copy1.x 和 copy2.x 指向同一個對象的引用,所以他們嚴格相等。
ES2015增加的另一個有用特性是rest參數,它允許JS使用……將值表示為數組:
在上述代碼中,arr中的第一項分配給x,其餘元素分配給rest變數。這種模式稱為數組析構,非常流行,Ecma技術委員會決定為對象提供類似的功能:
這段代碼使用析構賦值中的rest屬性將剩餘的可枚舉屬性複製到一個新對象中。注意,rest屬性必須始終出現在對象的末尾,否則將拋出錯誤:
此外,在對象中使用多個rest語法會拋異常,除非它們是嵌套的:
Rest/Spread 特性支持
Node.js:
8.0.0 (需要 --harmony 運行環境)
8.3.0 (完全支持)
二、非同步迭代
遍歷是編程的一個重要部分。JS提供了for、for…in和while以及map()、filter()和forEach()等遍曆數據的方法。在ES2015則引入了迭代器介面。
包含Symbol.iterator屬性的對象是可迭代對象,如字元串和集合對象(如Set、Map和Array)。如下為迭代遍歷的示例:
Symbol.iterator是指定返回迭代器的函數. 迭代器包含next()方法,返回包含value和done屬性的對象。其中value為下一個元素,done為布爾值,表示遍歷是否結束。
普通對象進行迭代需要定義Symbol.iterator屬性。示例如下:
對象的迭代器通過Object.keys()方法獲取屬性名數組,將其賦值給values常量,同時定義一個默認值為0的計數器。當迭代器開始執行時,會返回一個包含next()方法的對象。該方法會返回包含value和done的對象,value為下一迭代值,done為布爾值,表示迭代器是否到達終點。
上述實現方式還是過於複雜,可以通過generator函數簡化:
在該generator函數中,利用for in循環枚舉生成屬性值。結果與前面的示例完全相同,但是要短得多。
迭代器的缺點是不適合表示非同步數據源。ES2018的解決方案是非同步迭代器和非同步迭代。非同步迭代器與傳統迭代器的不同之處在於,它沒有返回形式的普通對象,而是返回一個Promise,其resolve返回對象。一個可非同步迭代對象中包含Symbol.asyncIterator屬性(而不是Symbol.iterator),其功能為返回一個非同步迭代器。
如下示例應該會使這一點更清楚:
注意,promise 迭代器並不能代替非同步迭代器。雖然一個普通的同步迭代器可以非同步地確定值,但是它仍然需要同步地確定「完成」的狀態。
當然,您同樣可以使用generator函數簡化該過程,如下所示:
同樣,非同步迭代執行後會返回一個包含next()方法的對象。調用next()會返回一個包含的對象,而value值則變為一個promise對象
在可迭代對象上迭代的一個簡單方法是使用for of,但由於非同步迭代對象的value和done並不是同步指定的,因此for of並不適用。基於此,ES2018提供了for await of方法。讓我們來看一個例子:
在本代碼中,for await of語句隱式調用了Symbol.asyncIterator方法。在每次循環時,都會調用迭代器的next()方法,該方法返回一個promise。promise對象的value屬性將被讀入x變數。循環繼續,直到返回對象的done屬性的值為true。
注意:for await of語句僅在非同步生成器和非同步函數中有效。違反此規則會報SyntaxError錯誤。
next()方法可能返回一個包含rejects的promise。要優雅地處理,你可以把for await of用try catch包裹,如下所示:
非同步迭代器支持
Node.js:
8.10.0 (需要--harmony\ async\ iteration標誌)
10.0.0 (全部支持)
ES2018的另一個令人興奮的新特性是finally()方法。幾個JavaScript庫以前實現過類似的方法,這在許多情況下都很有用。這鼓勵Ecma技術委員會正式將finally()添加到規範中。無論promise的結果如何,finally()方法中的代碼都會執行。讓我們看一個簡單的例子:
無論操作是否成功,當您需要在操作完成後進行一些清理時,finally()方法就派上用場了。在這段代碼中,finally()方法在請求數據之後隱藏loading,無論請求是否成功。
您可以使用promise來實現相同的結果,使用then(func, func)而不是promise.finally(func),但是你必須在fulfillment handler和rejection handler中重複相同的代碼,或者為它聲明一個變數:
與then()和catch()一樣,finally()方法總是返回一個promise,因此可以鏈接更多的方法。通常,您希望使用finally()作為最後一個鏈,但是在某些情況下,例如在發出HTTP請求時,最好將另一個catch()鏈接起來,以處理finally()中可能出現的錯誤。
Node.js:10.0.0 (全部支持)
四、新的正則表達式特性
ES2018為正則表達式添加了四個新特性,進一步提高了JavaScript的字元串處理能力。這些特點如下:
s (dotAll) 標誌
命名捕獲組
Lookbehind 後行斷言
Unicode屬性轉義
s (dotAll) 標誌
點(.)是正則表達式模式中的一個特殊字元,它匹配除換行符(如換行符(\n)或回車符(\r)之外的任何字元。匹配所有字元(包括換行符)的一種方法是使用一個包含兩個短字元的字元類,比如[\d\D]。這個表達式查詢數字(\d)或非數字(\D)字元。因此,它匹配任何字元:
ES2018引入了一種模式,在這種模式中,點(.)可以用來實現相同的結果。通過在原正則表達式基礎上添加s表示,可以激活該模式:
使用標誌位來定義新行為的好處是向後兼容性。因此,使用點字元的現有正則表達式模式不受影響。
命名捕獲組
在一些正則表達式模式中,使用數字進行匹配可能會令人混淆。例如,使用正則表達式/(\d)-(\d)-(\d)/來匹配日期。因為美式英語中的日期表示法和英式英語中的日期表示法不同,所以很難區分哪一組表示日期,哪一組表示月份:
ES2018引入了使用(?…)語法的命名捕獲組。因此,匹配日期的模式可以用一種不那麼模稜兩可的方式來寫:
你可以在一個正則表達式中使用\k語法重複調用名稱捕獲組。例如,要在一個句子中找到連續重複的單詞,可以使用/\b(?\w )\s \k\b/:
要將命名捕獲組插入replace()方法的替換字元串中,需要使用$構造。例如:
Lookbehind後行斷言
ES2018將lookbehind後行斷言引入JavaScript,以前JavaScript只支持前行斷言。後行斷言由(?
還有一種負向後行斷言,表示為(?
Unicode 屬性轉義
ES2018提供了一種新的轉義序列類型,稱為Unicode屬性轉義,可以匹配所有的Unicode。你可以使用\p來匹配所有的Unicode數字,例如,假設你想匹配的Unicode字元?字元串:
同樣的,你可以使用\p來匹配所有的Unicode單詞字元:
同樣有一個負向的Unicode屬性轉義模板 \P{...}:
除了字母和數字之外,Unicode屬性轉義中還可以使用其他一些屬性。您可以在現行規範中找到受支持的Unicode屬性列表。
新正則表達式支持
Node.js:
8.3.0 (需要 --harmony 標誌)
8.10.0 (支持 s (dotAll) 標誌和後行斷言)
10.0.0 (全部支持)
五、 模板文字修訂
當模板文字前緊跟著一個表達式時,它被稱為帶標記的模板文字。當您想用函數解析模板文字時,帶標記的模板就派上用場了。考慮下面的例子:
在這段代碼中,模板文字調用了一個標記表達式(函數):修改字元串中的變數部分。
在ES2018之前,標記模板文字具有與轉義序列相關的語法限制。後跟特定字元序列的反斜杠被視為特殊字元:十六進位轉義的\x、unicode轉義的\u和八進位轉義的\u。因此,像「C:\xxx\uuu」或「\ubuntu」這樣的字元串被解釋器認為是無效的轉義序列,並且會拋出一個SyntaxError。
ES2018從標記模板中移除這些限制,並不是拋出錯誤,而是將無效的轉義序列表示為undefined:
注意,在常規模板文字中使用非法轉義序列仍然會導致錯誤:
模板文字修訂支持
Node.js:
8.3.0 (需要 --harmony 標誌)
8.10.0 (全部支持)
總結
TAG:JavaScript |