ECMAScript2021に追加予定のJavaScriptの機能をみてみる。

どうも、アラサーマークアップエンジニアです。
この記事は、[ゆめみ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yumemi)の6日目の記事です。

JavaScriptの仕様は、TC39というECMAScriptの仕様を定める委員会が、毎年6月頃に新しい仕様を発表しています。
今年は[ECMAScript2020](https://www.ecma-international.org/ecma-262/)という仕様でしたが、来年は[ECMAScript2021](https://tc39.es/ecma262/)の仕様となります。

この記事では、現在ECMAScript2021でリリースされることが、確定している新しい構文について見ていこうと思います。


## そもそも新しい仕様はどうやって決まるの？

[TC39/proposals](https://github.com/tc39/proposals)のリポジトリに現在検討中の仕様がまとまっています。仕様にはstageというものが存在し、ドラフト→レビュー→実装→テスト→2つ以上のブラウザが実装という順番で最終的にstage4になると仕様が確定します。詳しくは、[こちら](https://tc39.es/process-document/)にまとまっています。

2020年12月時点でstage4となっているのが、

- String.prototype.replaceAll
- Promise.any
- WeakRefs
- Logical Assignment Operators
- Numeric separators

になります。

※stage3やstage2など仕様が確定していないものについてもBabelを通して使うことができたり、一部TypeScriptに機能として盛り込まれているものもあります。

## String.prototype.replaceAll

文字列の置換をする時は今まで**正規表現**もしくは、**split()とjoin()を駆使する**方法がありました。

```JavaScript
'アラサーマークアップエンジニア'.replace(/アラサー/g, 'アラフォー'); // 正規表現
'アラサーマークアップエンジニア'.split('アラサー').join('アラフォー'); // splitとjoin
// どちらも'アラフォーマークアップエンジニア'と置換される。
```
文字列型の場合は最初の1つしか置換してくれないので、全部置換したい場合はどうしても正規表現の``g``オプションを使うしかありませんでした。

上記を解消したのが``replaceAll（）``です。

```JavaScript
const text = 'javascript javascript JavaScript';
const regex = /javascript/g;
const regex2 = /javascript/gi;

console.log(text.replaceAll(regex, 'TypeScript'));
// "TypeScript TypeScript JavaScript"

console.log(text.replaceAll(regex2, 'TypeScript'));
// "TypeScript TypeScript TypeScript"

```

## Promise.any
振り返るとES2020では``Promise.allSettled()``が追加され、allでは実現できなかったrejectされるものがあっても全ての処理が実行されることができるようになりました。

今回新しく追加されたanyは、raceでは実現できなかったことが実現できます。
raceは最初の1つがresolveする前にrejectしたPromiseがあったらそこで全体がrejectするという挙動をします。

```javascript

const fetcher = [
  fetch('https://api.github.com'),
  fetch('https://api.github.com'),
  fetch('https://api.github.com'),
  fetch('https://api.github.com'),
  new Promise((resolve, reject) => {
    setTimeout(() => reject('中断したよ！'), 10)
  })
]

try {
  console.log(await Promise.race(fetcher))
} catch(err) {
  console.error(err) //中断したよ！
}

```

上記だと中断してしまいますが、anyだと最初の1つが成功するとその1つだけを返してくれます。


```JavaScript

const fetcher = [
  fetch('https://api.github.com'),
  fetch('https://api.github.com'),
  fetch('https://api.github.com'),
  fetch('https://api.github.com'),
  new Promise((resolve, reject) => {
    setTimeout(() => reject('中断したよ！'), 10)
  })
]
try {
  console.log(await Promise.any(fetcher)) // レスポンスが返ってくる
} catch(err) {
  console.error(err) 
}

```
例えば、100リクエスト中99リクエストが失敗して1つだけ成功したら、その結果を返してほしいときに使うのがanyになります！


## 他のPromiseとの比較
ざっくり使い分けはこうです。上記のコードを使ってご自身でPromiseのメソッドを変更して試してみてください！

Promise.all()： 全部成功するまで続けて1つでも失敗したら処理が中断される。
Promise.allSettled(): 全部成功になるまで続けて失敗せず処理を最後まで実行する。
Promise.any(): 1つでも成功するとその後失敗しても成功のレスポンスを返す。
Promise.race(): 1つでも失敗すると中断される。

## WeakRefs

いわゆる弱参照の機能です。説明しようかとも思ったのですが、既にuhyoさんによる[詳しい記事](https://qiita.com/uhyo/items/5dc97667ba90ce3941cd)がありましたので、そちらに任せます！

## Logical Assignment Operators
JavaScriptには``+=``や``&=``などの二項演算子はありましたが、``&&=``や``||=``などはありませんでした。特に今まで疑問にも思わなかったのですが言われてみると確かに！と思いました。何でなんでしょうかね。。

今回のLogical Assignment Operatorsでは``&&=``と``||=``されに``??=``が新しく追加されました。

```JavaScript
let a = true
a &&= false
// false

let b = true
b ||= false
// true

let c = null
c ??= 1
// 1

```

## Numeric separators
既に使えていたものですが今回ちゃんと仕様として入ります。
数値のリテラルに``_``を入れて数値を読みやすくするものです。

```JavaScript
12345678901234567890 === 1_2_3_4_5_6_7_8_9_0_1_2_3_4_5_6_7_8_9_0
// true

```
ただしアンダースコアを2回連続で書くと構文エラーとなります。


## おわりに
今回はstage4に絞りましたが、stage3にはTop-level awaitやImport Assertions、stage2にはデコレーターや新しい日付オブジェクトとして注目されているTemporalなどがあり、今後も楽しみな仕様沢山あります。日々キャッチアップを怠らず老害と言われないように頑張りましょう！！

明日はゆめみといえばこの人！@Yametaroさんの「0歳娘「パパ、型を作る関数はないの？」」です！乞うご期待！！