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

2020-12-28

この記事は、ゆめみ Advent Calendar 2020の6日目の記事の転記です。

元記事はこちら

どうも、アラサーマークアップエンジニアです。

JavaScriptの仕様は、TC39というECMAScriptの仕様を定める委員会が、毎年6月頃に新しい仕様を発表しています。 今年はECMAScript2020という仕様でしたが、来年はECMAScript2021の仕様となります。

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

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

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

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

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

になります。

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

String.prototype.replaceAll

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

'アラサーマークアップエンジニア'.replace(/アラサー/g, 'アラフォー'); // 正規表現
'アラサーマークアップエンジニア'.split('アラサー').join('アラフォー'); // splitとjoin
// どちらも'アラフォーマークアップエンジニア'と置換される。

文字列型の場合は最初の1つしか置換してくれないので、全部置換したい場合はどうしても正規表現のgオプションを使うしかありませんでした。

上記を解消したのがreplaceAll()です。

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するという挙動をします。

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つだけを返してくれます。

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さんによる詳しい記事がありましたので、そちらに任せます!

Logical Assignment Operators

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

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

let a = true
a &&= false
// false

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

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

Numeric separators

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

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歳娘「パパ、型を作る関数はないの?」」です!乞うご期待!!


ソースコードはこちらのリポジトリにあります。

Google Analyticsを使っています。