JavaScriptのES2021で追加された新機能まとめ
2022/06/22追記
最新仕様ES2022がリリースされたので、新しく記事を書きました。
JavaScriptの仕様はECMAScriptで、ECMAScript 2015(ES2015)、ECMAScript 2016(ES2016)...というように毎年進化を続けています。
これまでの仕様はES2020でしたが、先日2021年6月22日にES2021が正式仕様として承認されました。
ブラウザ対応も完了しており、全モダンブラウザ(Google Chrome・Firefox・Safari・Microsoft Edge)でES2021の全機能が使えます。
本記事では、ES2021すべての新機能をまとめて紹介します。
_
区切りで書ける
大きな数値を構文 |
---|
数値_数値_数値 |
▼ 簡単な例
100_000_000; // 1億(100,000,000)
説明
10000000
という数値を見たとき、それが「10,000,000」なのか「1,000,000」なのか、ぱっと見て区別をつけるのは難しいです。数字を_
(アンダースコア)で区切り、数値を読みやすくできるようになります。
100_000_000; // 1億(100,000,000)
12_234; // 1万2234(12,234)
`${1_000_000}ドルの夜景`; // 100万ドルの夜景
_
で区切られていても、通常の数値として扱えるので計算など各種数値の操作が可能です。
console.log(222_222 * 2);
// 結果: 444444
16進数の区切りでも入れられる
区切りは3桁ごとに入れる必要はなく、任意の箇所で入れられます。ただ、10進数の場合は3桁区切りにしておいたほうが他の開発者の混乱を招かないでしょう。
// OKだが読みづらい
1_23_4;
区切りは数値であれば何でも使えます。16進数で色表現をする際の表現としても便利です。
0xff_00_00; // 0xff0000
0xa0_b0_c0; // 0xa0b0c0
関連資料
文字列.replaceAll()
マッチした文字列をすべて置換できる構文 | 戻り値 |
---|---|
文字列.replaceAll(文字列または正規表現, 文字列) |
String |
▼ 簡単な例
"👺👺👺😈😈😈".replaceAll("😈", "🔥");
// 結果: "👺👺👺🔥🔥🔥"
説明
replaceAll()
とは、引数にマッチした文字列をすべて置換できるメソッドです。
従来、文字列の置換用のメソッドとして、文字列.replace()
メソッドがありました。replace()
メソッドは、正規表現または文字列を引数に取り、マッチした文字列を置換するメソッドです。引数が文字列の場合、「最初にマッチした文字列だけを」置換します。すべての文字列を置換するためには、引数に正規表現を使う必要がありました。
replaceAll()
は、replace()
と異なり文字列の引数でもすべての文字列を置換できます。
文字列.replaceAll()
の挙動確認
「猫田猫男は猫好きだ」という文字列の、「猫」を「犬」に変換する例で考えてみましょう。文字列"猫"
を引数にしてreplace()
メソッドを使った場合、最初の「"猫"
」しか置換されません。
"猫田猫男は猫好きだ".replace("猫", "犬");
// 結果: "犬田猫男は猫好きだ"
すべての「猫」を「犬」に変換するためには、引数を正規表現にしてg
フラグを指定し、「/猫/g
」とする必要があります。
"猫田猫男は猫好きだ".replace(/猫/g, "犬");
// 結果: "犬田犬男は犬好きだ"
ES2021のreplaceAll()
を使えば、正規表現を使わずとも引数の文字列すべてを置換できます。よりシンプルに文字列の一括置換ができるようになったと言えるでしょう。
"猫田猫男は猫好きだ".replaceAll("猫", "犬");
// 結果: 「"犬田犬男は犬好きだ"」
▼ 実行結果
関連資料
Promise.any
複数のPromiseのうち、最初のresolveを待つ構文 | 戻り値 |
---|---|
Promise.any(Promiseの配列) |
Promise |
▼ 簡単な例
Promise.any([
promise1, promise2, promise3
]).then(first => {
// 3つのpromiseのうち、最初に解決したpromiseが出力される
console.log(first)
});
説明
Promise
では非同期処理を扱えますが、制作の現場では複数の非同期処理を同時に扱いたいことが多いでしょう。Promise.any
とは、複数のPromiseのうち、どれか1つでもresolveしたらその時点で解決されるPromiseです。最初のresolveがあるまでは、rejectは無視されます。
Promise.any()
の挙動確認コード
次のコードでPromise.any()
の挙動を確認してみましょう。3つのPromiseは、それぞれ次の挙動をします。
-
promise1
: 1秒後に「reject」されます -
promise2
: 2秒後にresolveします -
promise2
: 3秒後にresolveします
promise1
は一番完了が早いですが、rejectされるため無視されます。promise2
がresolveされるのが一番早いため、Promise.any
ではpromise2
をもってresolveします。
// 1秒後に「reject」されるPromise
const promise1 = new Promise((resolve, reject) =>
setTimeout(reject, 1000, "promise1")
);
// 2秒後にresolveするPromise
const promise2 = new Promise((resolve) =>
setTimeout(resolve, 2000, "promise2")
);
// 3秒後にresolveするPromise
const promise3 = new Promise((resolve) =>
setTimeout(resolve, 3000, "promise3")
);
Promise.any([promise1, promise2, promise3]).then((resolve) => {
console.log(resolve);
});
▼ 実行結果
resolveされるPromiseが1つもない場合は、AggregateError
でrejectされます。
Promise.race()
との違い
Promise.any()
に似た処理として、Promise.race()
があります。
■ Promise.any()
引数のPromiseが最初に「resolveした時点で」終了する
■ Promise.race()
引数のPromiseが最初に「終了(resolveまたはreject)した時点で」終了する
▼ Promise.race()
の実行結果
他のPromiseの複数処理
ES2015で導入されたPromise.all()
、ES2020で導入されたPromise.allSettled()
など、Promise
の複数処理はいくつかあります。この機会にそれぞれとの違いを確認しておくとよいでしょうw。
関連資料
??
や||
や&&
と=
を組み合わせて使える演算子
構文 |
---|
a ??= b |
`a |
a &&= b |
▼ 簡単な例
let a = null;
a ??= "🐈";
console.log(a); // 結果: "🐈"
let b = "🐷";
b ??= "🐈";
console.log(b); // 結果: "🐷"
説明
??=
演算子、||=
演算子、&&=
演算子とは、??
・||
・&&
と=
を組み合わせられる演算子です。
??=
演算子
??=
演算子とは、a
がnull
かundefined
のときに、a
にb
を代入するための演算子です。
ES2020では、??
演算子が実装されました。a ?? b
という形で用い、a
がnull
またはundefined
のときのみb
を返せます。||
演算子はa
がfalsyなもの(0
や""
やfalse
)のときもb
を返すのに対して、厳密にnull
やundefined
を判定できるので、開発の現場では重宝する処理です。
??=
演算子は、??
に=
を組み合わせたもの。次の挙動と同じ意味です。
// aがnullかundefinedのときに、aにbを代入する
a ?? (a = b);
const human = { name: "田中" }
というオブジェクトのプロパティを通して、??=
の挙動を確認してみましょう。
human.age ??= 18
でage
プロパティに18
の代入を試みています。age
プロパティはundefined
なので、18
が代入されます。
human.name ??= "鈴木"
では、name
プロパティがundefined
ではないので、"鈴木"
は代入されません。
const human = { name: "田中" };
human.age ??= 18;
// hunan.ageはundefinedなので18が代入される
human.name ??= "鈴木";
// hunan.nameはnullではないので何も代入されない
console.log(human);
// 結果: {name: "田中", age: 18}
▼ 実行結果
||=
演算子
a
がfalsyなものの場合に、a
にb
を代入します。
let a = 0;
a ||= "🐈";
console.log(a); // 結果: "🐈"
let b = "🐷";
b ||= "🐈";
console.log(b); // 結果: "🐷"
||=
は、たとえばHTML要素のinnerHTML
のデフォルト値を設定するようなケースで使えます。次のコードでは、.foo
要素の中身が空の場合に、<p>値なし</p>
の要素を代入できます。
document.querySelector(".foo").innerHTML ||= "<p>値なし</p>";
&&=
演算子
a
がtruthyなものの場合に、a
にb
を代入します。
let a = null;
a &&= "🐈";
console.log(a); // 結果: null
let b = "🐷";
b &&= "🐈";
console.log(b); // 結果: "🐈"
関連資料
弱参照を作れるWeakRef
構文 | 戻り値 |
---|---|
new WeakRef(対象) |
WeakRef |
▼ 簡単な例
const myObject = { name: "田中" };
// myObjectへの弱参照が作られる
const ref = new WeakRef(myObject);
説明
WeakRef
は、JavaScriptにおいて弱参照を作れるオブジェクトです。参照はされているものの、参照先はガベージコレクションの対象となります。また、オブジェクトがガベージコレクトされた際、FinalizationRegistry
オブジェクトによりコールバックを実行できるようになりました。ただし、ガベージコレクション周りの処理は複雑であり、可能であれば使用を避けることがよいとされています(「tc39 / proposal-weakrefs」参照)。
WeakRefの詳しい内容は、@uhyoさんの解説記事がわかりやすいので、そちらを参照するとよいでしょう。
※ FinalizationGroup
はFinalizationRegistry
に読み替えてください
関連資料
対応環境
本記事で紹介したES2021の全機能は、各環境で使用可能です。
- Google Chrome
- Firefox
- Safari
- Microsoft Edge
- TypeScript
- Node.js
「ECMAScript compatibility table」で、細かい対応バージョンを確認できます。
※ 執筆時点では、TypeScriptの最新対応状況が反映されていないようです
ES2021を使って便利に開発しよう
本記事では正式仕様としてリリースされたES2021の新機能を紹介しました。どれも開発をラクにしてくれるものばかりで、筆者も積極的に開発の現場で使っています。ECMAScriptは次のES2022に向けて仕様策定がすでに始まっています。top levelでのawait
やclass fieldなど、また便利な機能が入ってきそうです。新しい機能をキャッチアップし、楽しく開発していきましょう。
ES2021のLanguage Specificationは、こちらから確認できます。
TwitterでもJavaScriptやCSSの最新情報を発信しています!
Discussion
文字列.replaceAll()の挙動確認
でしょうか?
ご指摘ありがとうございます! typoでしたので修正しました📝
Promise.any()
とPromise.race()
の違いについて説明を加えました。記事の情報、ありがたいです。
1点、細かいところですみません。 hunan.age ⇒ hunan.name となるかと思いました。
ご指摘ありがとうございます!
更新いたしました🐈