JavaScriptの‍ES2019で追加された新機能まとめ

（2021/06/24追記）
ES2021の記事を公開しました。

- [正式仕様リリース！ JavaScriptの最新仕様ES2021で追加された新機能まとめ - Zenn](https://zenn.dev/tonkotsuboy_com/articles/es2021-whats-new)

---

（2020/02/03追記）
ES2020の記事を公開しました。

- [JavaScriptの次の仕様ES2020で追加されることが決定した新機能まとめ \- ICS MEDIA](https://ics.media/entry/200128/)

---

本記事ではES2019の新機能を解説しています。記事末尾では、個人的に追加を期待していたけれどまだステージ3の機能についても紹介しています。

- ES2019仕様書：「[ECMAScript® 2019 Language Specification](https://www.ecma-international.org/ecma-262/10.0/index.html)」

# ES2019で追加された新機能

## 配列のフラット化 - `flat()`, `flatMap()`
配列をフラット化するためのメソッド。フラット化とは、多階層の配列を一階層にすることです。

`flat()`メソッドの挙動は次のとおりです。

```js:flat()メソッド
[[1, 2], 3, 4].flat();
// 結果：[1, 2, 3, 4]
```

`flatMap()`メソッドは、配列をマッピングしたあとにフラット化します。たとえば、次のような二次元の配列から、「`favorite`」だけからなる配列を作りたいケースを考えてみましょう。

```js:flatMap()メソッド
const MyData = [
  {
    name: "菅原さん",
    favorite: [ "大豆", "プロテイン", "つけ麺"]
  },
  {
    name: "山根さん",
    favorite: ["プロテイン", "ビタミンC"]
  },
  {
    name: "鹿野さん",
    favorite: [ "ラーメン", "つけ麺", "軟骨の唐揚げ"]
  }
];
```

`flatMap()` メソッドを使わない場合は、次のような記述が必要です。

```js
MyData
  .map(data => data.favorite)
  .flat();
// 結果：["大豆", "プロテイン", "つけ麺", /*中略*/ "軟骨の唐揚げ"]
```


`flatMap()` メソッドを使うと、次のように記述できます。**フラット化したあとにマッピングではないこと**に注意しましょう。

```js
MyData
  .flatMap(data => data.favorite);
// 結果：["大豆", "プロテイン", "つけ麺", /*中略*/ "軟骨の唐揚げ"]
```

公式ドキュメント

 - [Array\.prototype\.flatMap & Array\.prototype\.flat](https://tc39.github.io/proposal-flatMap/)

## キー・値のペアからオブジェクトを生成 - `Object.fromEntries()`
キー・値のペアからオブジェクトを生成するスタティックメソッド。挙動は次のとおりです。

```js:Objec.fromEntries()
Object.fromEntries([["id", 16], ["name", "鈴木"]]);
// 結果：{id: 16, name: "鈴木"}
```

`Map`オブジェクトでもキー・値のペアを渡して初期化できましたが、それと似た挙動です。

```js:Mapの初期化の参考
new Map([[1, "高橋"], [2, "後藤"]]);
// 結果： {1 => "高橋", 2 => "後藤"}
```

公式ドキュメント

- [TC39 proposal for Object\.fromEntries](https://github.com/tc39/proposal-object-from-entries)

## 文字列の先頭または末尾の空白を除去 - `trimStart()`, `trimEnd()`
文字列の先頭または末尾の空白を除去するメソッドです。

`trimStart()`メソッドは、文字列の先頭の空白を除去します。

```js:trimStart()メソッド
"  寿司ざんまい　　　".trimStart();
// 結果："寿司ざんまい　　　"
```

`trimEnd()`メソッドは、文字列の末尾の空白を除去します。

```js:trimEnd()メソッド
"  寿司ざんまい　　　".trimEnd();
// 結果："  寿司ざんまい"
```

なお、文字列の両端を取り除く`trim()`メソッドはES2015で追加済みです。

```js:trim()メソッド（ES2015で追加済）
"  寿司ざんまい　　　".trim();
// 結果："寿司ざんまい"
```


公式ドキュメント

- [String\.prototype\.trimStart/trimEnd](https://tc39.github.io/proposal-string-left-right-trim/)

## `Symbol`の説明を返す - `description`
`Symbol`の説明（`description`）を返すプロパティーです。説明とは、デバッグ用に`Symbol`を区別するためのものです。

```js:Symbolのdescription
Symbol("矢部").description;
// 結果："矢部"
```

公式ドキュメント

- [Symbol description accessor](https://tc39.github.io/proposal-Symbol-description/)

## `try catch`の`catch`ブロックで引数指定箇所を省略可能に

`try catch`の`catch`ブロックでは、引数指定の`(error)`部分を記載しないとシンタックスエラーになっていました。

```js:従来のtry-catch
try {
  throw new Error("🙅");
} catch(error) {    // (error)の指定は必須
  console.warn("エラーをキャッチしました")
}
```

`try catch`の`catch`ブロックで、引数指定の箇所の`(error)`を記載しなくても良くなりました。

```js:ES2019のtry-catch
try {
  throw new Error("🙅");
} catch {   // (error)の記載はしなくても良い
  console.warn("エラーをキャッチしました")
}
```

公式ドキュメント

- [proposal for ECMAScript to allow omission of the catch binding](https://github.com/tc39/proposal-optional-catch-binding)

## 関数を`toString()`で文字列に変換した際の仕様が改訂

関数を文字列化した場合、従来はこのような挙動でした。

```js:従来
function /* こんにちは */ myFunction  () {}

myFunction.toString();
// 結果："function myFunction() {}"
// コメントや文字列が削除される
```

ES2019からは以下の挙動が正式な仕様となります。

```js:ES2019
function /* こんにちは */ myFunction  () {}

myFunction.toString();
// 結果："function /* こんにちは */ myFunction  () {}"
// コメントや文字列が保持される
```

公式ドキュメント

- [Function\.prototype\.toString revision](https://tc39.github.io/Function-prototype-toString-revision/)

## 行区切り文字や段落切り文字をエスケープなしに扱えるように - ECMA-262構文をJSONのスーパーセットに拡張

JSONの元々の仕様として、行区切り文字（U+2028、Line Separator）や段落区切り文字（U+2029、Paragraph Separator）をエスケープなしに扱えます。

```json:JSONでは元々エラーなし
JSON.parse('"\u2029"');  // エラーなし
```

※ `\u番号`はユニコード文字を示す

一方で、JavaScriptで行区切り文字や段落区切り文字を扱う場合には、エスケープをしないとシンタックスエラーになっていました。

```js:従来のJavaScriptのコードではシンタックスエラー
const PS = eval("'\u2029'"); // エラー
```
ES2019からは、シンタックスエラーに**ならない**のが仕様となり、JSONの挙動と同じになります。

```js:ES2019ではシンタックスエラーにならないのが仕様
const PS = eval("'\u2029'"); // エラーなし
```

公式ドキュメント

- [Proposal to make all JSON text valid ECMA\-262](https://github.com/tc39/proposal-json-superset)

※ 2019/01/31 @mandel59 さんのコメントを受け、説明を改善しました

## `JSON.stringify()`の取り扱い改善

文字列の�（U+D834: INVALID CHARACTER、[参考リンク](https://www.charbase.com/d834-unicode-invalid-character)）などをエスケープし、`JSON.stringify()`でJSON文字列に変換するケースを考えます。

```js:このJavaScriptコードで解説します
JSON.stringify('\uD834')
```

従来は次のようになっていました。次に示すのは、Google Chrome 71での実行結果です。

▼ Google Chrome 71でのコンソール表示結果

![](https://qiita-image-store.s3.amazonaws.com/0/67884/0b343462-e3a0-9954-1174-3df99f78eada.png)

ES2019では、エスケープされたまま出力されるのが仕様となります。次に示すのは、Google Chrome **74**での実行結果です。

▼ Google Chrome 74でのコンソール表示結果

![](https://qiita-image-store.s3.amazonaws.com/0/67884/737c3049-2b43-055a-b923-b633550e664e.png)

公式ドキュメント

- [Proposal to prevent JSON\.stringify from returning ill\-formed strings](https://github.com/tc39/proposal-well-formed-stringify)

# Google Chrome 73よりES2019の新機能はすべて使える

Google Chrome 73より、ES2019の新機能はすべて使えるとのことです。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">As of <a href="https://twitter.com/v8js?ref_src=twsrc%5Etfw">@v8js</a> v7.3 / Chrome 73, all of these ES2019 features are available by default. Enjoy! <a href="https://t.co/vtvx8VTRYw">https://t.co/vtvx8VTRYw</a></p>&mdash; V8 (@v8js) <a href="https://twitter.com/v8js/status/1090380906546683904?ref_src=twsrc%5Etfw">January 29, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Google Chrome 74（Canary）のコンソールで、今回紹介したES2019用のコードを実行した際のキャプチャーです。すべて仕様通りに動作していることがわかります。


▼ Google Chrome 74（Canary）の動作結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/67884/3b7e984f-2eff-3498-9f1a-3a3d533cd36f.png)

# ES2019への追加を期待していたが、まだステージ3の機能 

次の機能がES2019への追加されることを個人的に期待していましたが、現時点ではまだステージ3です。早く正式仕様になってほしいと思いつつ、議論の進捗を見守っています。

- [Dynamic Import](https://github.com/tc39/proposal-dynamic-import)
- [BigInt](https://github.com/tc39/proposal-bigint)
- [クラスフィールド](https://github.com/tc39/proposal-class-fields)
- [プライベートフィールド](https://github.com/tc39/proposal-private-methods)


# 最後に
配列のフラット化とOptional Catch Bindingが正式仕様になることが嬉しく思いました。

本記事で紹介したES2019の仕様は、Chrome 73ですべて対応済みです。その他のブラウザーについては、TypeScript・Babelとポリフィルで対応するとよいでしょう。

策定が終了した仕様の一覧は、次のURLで確認できます。

- [Finished Proposals - tc39](https://github.com/tc39/proposals/blob/master/finished-proposals.md)

ICS MEDIAで発信しているJavaScriptの資料もあわせてどうぞ。

- [「JavaScriptコードレシピ集」を執筆しました！ \- ICS MEDIA](https://ics.media/entry/19765)
- [2019年までに見直しておきたい CSS・JavaScriptの手法 \- Speaker Deck](https://speakerdeck.com/tonkotsuboy_com/2019nian-madenijian-zhi-siteokitai-cssjavascriptfalseshou-fa)
- [2018年に見直した現代的なJavaScriptの記法を紹介するぜ \- ICS MEDIA](https://ics.media/entry/17262)