ECMAScript 2019(ES10)新特性簡介

flydean 發表於 2021-05-04

簡介

ES10是ECMA協會在2019年6月發行的一個版本,因為是ECMAScript的第十個版本,所以也稱為ES10.

今天我們講解一下ES10的新特性。

ES10引入了2大特性和4個小的特性,我們接下來一一講解。

Array的新方法flat和flatMap

在ES10中,給Array引入了兩個新的方法,分別是flat和flatMap。

先來看一下flat。

我們看一下 Array.prototype.flat() 的定義:

.flat(depth = 1): any[]

flat的作用是將Array中的Array中的內容取出來,放到最頂層Array中。我們可以傳入一個depth引數,表示的是需要flat的Array層級。

舉個例子:

> [ 1,2, [3,4], [[5,6]] ].flat(0) // no change
[ 1, 2, [ 3, 4 ], [ [ 5, 6 ] ] ]

> [ 1,2, [3,4], [[5,6]] ].flat(1)
[ 1, 2, 3, 4, [ 5, 6 ] ]

> [ 1,2, [3,4], [[5,6]] ].flat(2)
[ 1, 2, 3, 4, 5, 6 ]

當depth=0的時候,就表示不會對Array內建的Array進行flat操作。

我們再看一下Array.prototype.flatMap()的定義:

 .flatMap<U>(
  callback: (value: T, index: number, array: T[]) => U|Array<U>,
  thisValue?: any
): U[]

flatMap是map和flat的結合,下面的兩個操作是等價的:

arr.flatMap(func)
arr.map(func).flat(1)

我們看幾個flatMap的例子:

> ['a', 'b', 'c'].flatMap(x => x)
[ 'a', 'b', 'c' ]
> ['a', 'b', 'c'].flatMap(x => [x])
[ 'a', 'b', 'c' ]
> ['a', 'b', 'c'].flatMap(x => [[x]])
[ [ 'a' ], [ 'b' ], [ 'c' ] ]

> ['a', 'b', 'c'].flatMap((x, i) => new Array(i+1).fill(x))
[ 'a', 'b', 'b', 'c', 'c', 'c' ]

Object的新方法fromEntries

Object.fromEntries的主要作用就是通過給定的[key,value],來建立新的Object物件。

var newObj =  Object.fromEntries([['foo',1], ['bar',2]]);
console.log(newObj);
{ foo: 1, bar: 2 }

上面例子中,我們通過給定的兩個key-value對,建立了新的object物件。

和fromEntries相反的方法,就是Object.entries,用來遍歷物件屬性。

還是剛剛的例子,我們再呼叫一下Object.entries方法:

console.log(Object.entries(newObj));
[ [ 'foo', 1 ], [ 'bar', 2 ] ]

String的新方法trimStart和trimEnd

JS中已經有了trim的方法,可以消除String前後的空格。

> '  abc  '.trim()
'abc'

但有時候可能需要消除前面或者後面的空格,ES10引入了trimStart和trimEnd方法:

> '  abc  '.trimStart()
'abc  '
> '  abc  '.trimEnd()
'  abc'

注意,有些瀏覽器可能已經有了trimLeft和trimRight方法,在EMCAScript規範中,他們和trimStart,trimEnd是等價的。

可訪問的Symbol的description屬性

我們在建立Symbol的時候,可以傳入一個description作為引數來構建Symbol:

const sym = Symbol('www.flydean.com');

在ES10之前,我們想要訪問Symbol的description是這樣做的:

console.log(String(sym));
//Symbol(www.flydean.com)

現在我們可以直接通過description屬性來訪問了:

console.log(sym.description);
//www.flydean.com

可忽略的catch引數

在傳統的寫法中,catch是要接受一個error引數的:

try {
  // ···
} catch (error) {
  // ···
}

但有時候我們已經知道這個異常是不重要的,或者說,我們想忽略掉這個異常,那麼在ES10中,我們可以省略這個error引數:

try {
  // ···
} catch {
  // ···
}

Array的穩定排序

Array有個sort功能,可以根據元素內容進行排序。

ES10中引入了穩定排序的概念,也就是說如果排序的key是相同的,那麼這些相同key的順序在排序中是不會發生變化的。

舉個例子:

const arr = [
  { key: 'b', value: 1 },
  { key: 'a', value: 2 },
  { key: 'b', value: 3 },
];
arr.sort((x, y) => x.key.localeCompare(y.key, 'en-US'));

我們根據key來進行排序,從而讓a,排在b前面,但是兩個key=b的元素位置是不會變化的。

console.log(arr);
[
  { key: 'a', value: 2 },
  { key: 'b', value: 1 },
  { key: 'b', value: 3 }
]

JSON.stringify

JSON是一個很方便的資料傳輸格式,它不像XML那麼複雜,優點就是體積小,便於傳輸。

根據RFC3629的規範,在公共環境中傳輸JSON,必須使用UTF-8進行編碼。

JSON text exchanged between systems that are not part of a closed
ecosystem MUST be encoded using UTF-8 [RFC3629].

在講JSON.stringify之前,我們先回顧一下ES6中的Escape sequences。

ES6中有三種escape:

  1. Hex escape:16進位制escape。轉義的是2位的16進位制。
  > '\x7A' === 'z'
  true
  1. Unicode escape:轉義的是4位的16進位制
 > '\u007A' === 'z'
  true
  1. Unicode code point escape:轉義的是1位或者多位的16進位制
  > '\u{7A}' === 'z'
  true

最後一個轉義是在ES6中引入的。

unicode字符集最後是要儲存到檔案或者記憶體裡面的,直接儲存的話,空間佔用太大。那怎麼存呢?使用固定的1個位元組,2個位元組還是用變長的位元組呢?於是我們根據編碼方式的不同,分成了UTF-8,UTF-16,UTF-32等多種編碼方式。

其中UTF-8是一種變長的編碼方案,它使用1-4個位元組來儲存。UTF-16使用2個或者4個位元組來儲存。

而UTF-32是使用4個位元組來儲存。這三種編碼方式中,只有UTF-8是相容ASCII的,這也是為什麼國際上UTF-8編碼方式比較通用的原因(畢竟計算機技術都是西方人搞出來的)。

我們知道在Unicode編碼中,U+D800到U+DFFF的這些字元是預留給UTF-16使用,如果我們輸入的是這個範圍內的字元的話,是無法被轉換成為UTF-8格式的。

這就是原來的JSON.stringify可能出現的問題。

在ES10中,JSON.stringify對於這些不可轉換成UTF-8的字元,直接返回對應的code unit escape sequences。

console.log(JSON.stringify('\u{D800}'));
"\ud800"

JSON 被歸為ECMAScript的子集

在之前,JSON不是ECMAScript的子集,從而導致有些可以在JSON中包含的字元,不能夠在ECMAScript的字面量中出現,比如U+2028 和U+2029 :

const sourceCode = '"\u2028"';
eval(sourceCode); // SyntaxError

JSON.parse(json); // OK

這次改變之後,我們在編碼的時候就不需要再去區分是JSON還是ECMAScript了。

Function的toString方法

在ES10中,如果Function可以通過以ECMAScript原始碼的方式表示的話,則toString會直接返回這個函式的程式碼:

> class C { foo() { /*hello*/ } }
> C.prototype.foo.toString()
'foo() { /*hello*/ }'

如果是一些native的方法,比如底層c或者c++實現的程式碼,則直接返回[native code]:

> Math.pow.toString()
'function pow() { [native code] }'

本文作者:flydean程式那些事

本文連結:http://www.flydean.com/ecmascript-10/

本文來源:flydean的部落格

歡迎關注我的公眾號:「程式那些事」最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!