Slide 1

Slide 1 text

ES2021/ES2022 yamashita(ky6yk)

Slide 2

Slide 2 text

もくじ - ESのバージョンとは - ECMAScriptの仕様決定プロセス - ES2021で追加された機能 - ES2022で追加された機能

Slide 3

Slide 3 text

ESのバージョンとは ESはECMAScriptの略でJavaScriptの標準規格。 ES2015(ES6)以降は毎年新しいバージョンがリリースされている。 バージョン リリース時期 1 1997年6月 2 1998年6月 3 1999年12月 4 破棄 5 2009年12月 5.1 2011年6月

Slide 4

Slide 4 text

ECMAScriptの仕様決定プロセス ES2015まではすべての仕様の合意が取れるまで延々と議論を続行 リリースされるまでに時間がかかり、言語の進化が停滞 問題解消のために仕様策定プロセスを変更

Slide 5

Slide 5 text

ECMAScriptの仕様決定プロセス 仕様に追加する機能がそれぞれ個別の提案として、5段階のステージに分けられる。 2か月に1度、ステージをすすめるかどうか議論する。 毎年6月頃にステージ4まで進んでいる機能をリリース。 参考:https://tc39.es/process-document/ ステージ ステージの概要 0 アイディアの段階 1 機能提案の段階 2 機能の仕様書ドラフトを作成した段階 3 仕様としては完成しており、ブラウザの実装やフィード バックを求める段階 4 仕様策定が完了

Slide 6

Slide 6 text

ES2021/2022の対応ブラウザ ES2021/2022の全機能はChrome・Safari・FireFox・Edgeで使えます。

Slide 7

Slide 7 text

ES2021

Slide 8

Slide 8 text

replaceAll 構文:文字列.replaceAll(文字列or正規表現,文字列) 既に存在するreplaceメソッドでは最初に一致した箇所のみしか書き換えられなかった。 そのため、replaceメソッドで全ての文字を置換するには正規表現を使う必要があった。 replaceAllメソッドが追加されたことで一致したすべての箇所を書き換えることが可能。 // これまでの書き方 "すもももももももものうち".replace(/も/g, 'MO'); // replaceAllを使った書き方 "すもももももももものうち".replaceAll("も", "MO"); // すMOMOMOMOMOMOMOMOのうち 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll

Slide 9

Slide 9 text

Promise.any 構文:Promise.any(Promiseの配列) 引数に渡されたPromiseのうち最初にresolveされたものを返す。 引数に与えられたPromiseが全てrejectedされた場合はErrorをグループ化する AggregateErrorが投げられる。 使いどころとしては商品画像をキャッシュまたはサーバーから取得したいとき(一番早く返 された物を使う)など const promise1 = Promise.reject(0); const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick')); const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow')); const promises = [promise1, promise2, promise3]; Promise.any(promises).then((value) => console.log(value));

Slide 10

Slide 10 text

Promise.anyとPromise.raceの違い Promise.any - 引数のPromiseが最初にresolveした時点で終了 Promise.race - 引数のPromiseが最初にresolveかrejectした時点で終了 - 使いどころとしては長いリクエストを送る場合などに、タイムアウト機能を実装するとき (一定時間たったらrejectを返すようにする)など const promise1 = new Promise((_,reject) => setTimeout(reject, 10, 'quick_reject')); const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick_resolve')); const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow_resolve')); const promises = [promise1, promise2, promise3]; Promise.race(promises).then((value) => console.log(value)).catch((error) => { console.log(error) }); // rejectが一番初めに解決されるpromise1のquick_rejectが出力される

Slide 11

Slide 11 text

ES2020の復習)Null合体演算子 構文:a??b ES2020でNull合体演算子(??)が追加された。 ??演算子では左辺aがnullish(nullまたはundefined)の場合に右の値bを返して、 それ以外の場合に左の値を返す。 const foo = null ?? 'default string' ; console.log(foo); // default stringが出力される const baz = 0 ?? 42; console.log(baz); // 0が出力される

Slide 12

Slide 12 text

Null合体代入 構文:a??=b Null合体代入では左辺aがnullish(nullまたはundefined)の場合に右の値bを代入する。 この構文を使うことで、初期値を設定するときに余計な分岐が不要になり実装がスッキリす る。 const a = { duration: 50 }; a.duration ??= 10; console.log(a.duration); // 50が出力される a.speed ??= 25; console.log(a.speed); // 25が出力される aがnullish aがnullishではない aに代入される値 b 代入されない

Slide 13

Slide 13 text

(復習) falsyな値/truthyな値 JavaScriptは条件文などで任意の値を強制的にBooleanに型変換する。 その時にfalseとみなされる値をfalsyまたはfalsyな値と呼ぶ。 逆に、trueとみなされる値はtruthyまたはtruthyな値と呼ぶ。 falsyな値:false, 数値の0, 空文字, Nan, undefined, null truthyな値:falsyな値以外

Slide 14

Slide 14 text

論理和代入 構文:a||=b aがfalsyな場合に、aにbを代入する。 let a = 0; a ||= 10; // aはfalsyな値なので10が代入される console.log(a); // 10が出力される let b = 1 b ||= 10; // bはtruthyな値なので代入されない console.log(b); // 1が出力される 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment aがtruthy aがfalsy aに代入される値 代入されない b

Slide 15

Slide 15 text

論理積代入 構文:a&&=b 左辺の値aがtruthyな場合に、左辺の値aに右辺の値bを代入する。 let a = 1; a &&= 2; // aはtruthyな値なので2が代入される console.log(a); // 2 が出力される let b = 0; b &&= 2; // 0はfalsyな値なので代入が行われない console.log(b); // 0 が出力される 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_AND_assignment aがtruthy aがfalsy aに代入される値 b 代入されない

Slide 16

Slide 16 text

数値の区切り文字 構文:数値_数値 数値を_(アンダースコア)で区切ることで、数値を読みやすくできる。 注意点 1. 連続して2つ以上のアンダースコアは許可されない(10__000など) 2. アンダースコアを先頭、末尾に置くことはできない(_100, 100_など) 3. 先頭の0のあとにアンダースコアを置くことはできない(0_1など) console.log(100_000_000) // 100000000 が出力される アンダースコアは出力されない 参考

Slide 17

Slide 17 text

(復習) 弱参照とは JavaScriptでは、使われなくなった参照はプログラムにとっては必要がないため ガベージコレクションによってメモリから削除される。 弱参照では、オブジェクトへの参照はあるが参照先のオブジェクトがガベージコ レクションされている可能性がある。 つまり、使おうとしたらオブジェクトが取得できない可能性もある。 役に立つケース:一時的なキャッシュなど(あれば嬉しいけど無くても困らないもの)

Slide 18

Slide 18 text

WeakRef 構文:new WeakRef(対象) JavaScriptにおいて弱参照を作れるオブジェクト。 構文:WeakRef.prototype.deref(対象) WeakRefオブジェクトの対象オブジェクトを返すか対象オブジェクトが既に回収さ れている場合はundefinedを返す。 let obj = { name: "object 1" }; const wref = new WeakRef(obj); console.log(wref.deref()); 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/WeakRef

Slide 19

Slide 19 text

ES2022

Slide 20

Slide 20 text

Class Fields これまでクラスフィールドを作りたいときはconstructor内で宣言するしかなかった。 ES2022からクラスフィールドが定義できるようになった。 // これまでの書き方 class HogeCounter { constructor () { this.count = 0; } } // 新しい書き方 class HigeCounter { // publicなクラスフィールド count = 0; } 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/Public_class_fields

Slide 21

Slide 21 text

Private Fields ES2022 からprivateフィールドやメソッドも使えるようになった。 privateフィールドには接頭辞に#を付ける。privateフィールドは外部からアクセ スできずに、アクセスしようとすると構文エラーが発生する。 class HogeCounter { #count; //privateなクラスフィールド constructor(count) { this.#count = count; } // privateなメソッドも作成可能 #doubleCount() { return this.#count * 2; } echoCount() { console .log(this.#doubleCount ()); } } const object = new HogeCounter(10); object.echoCount(); //20が出力される 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/Private_class_fields

Slide 22

Slide 22 text

Static Fields ES2022から静的なクラスフィールドやメソッドが使えるようになった。 staticなフィールドやメソッドはインスタンス化なしで使うことが出来る。 class HogeCounter { static count = 10; static echoDoubleCount () { console.log(this.count*2); } } console.log(HogeCounter.count); console.log(HogeCounter.echoDoubleCount ()); 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/static#calling_static_members_from_a_class_constructor_and_other_methods

Slide 23

Slide 23 text

.at 構文:array.at(index) インデックス可能なクラス(Array,Stringなど)で指定位置の値を取得可能。 []との違いはat()に負の値を入れることが出来る。 最後の値を取得したいときはarray.at(-1)とすることで取り出せる。 console.log("123456789".at(-1)) // 9が出力する console.log("123456789".at(0)) // 1が出力する 参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at

Slide 24

Slide 24 text

Top Level await これまではawaitが書けるのはasync関数の中だけだった。async関数の外でもawait 式が書けるようになった。 ただし、関数内では今まで通りasyncが必要。 // NG:関数ではasyncが必要 function hoge() { return await hige(); } // OK const result = await hoge(); 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/await#%E6%9C%80%E4%B8%8A%E4%BD%8D%E3%81%AE_await

Slide 25

Slide 25 text

Top Level awaitの実行順序 Top Level awaitを使うと実行順序が複雑になる。 Top Level awaitを使用しているファイル全体が1つの非同期関数のように機能する。 // 非同期関数内でawaitを使う場合 console.log("1"); (async () => { await new Promise(resolve => setTimeout((resolve), 3000)) console.log("3") })() console.log("2") モジュールの実行順序への影響:https://qiita.com/uhyo/items/0e2e9eaa30ec2ff05260 // Top Level awaitの場合 console.log("1"); await new Promise(resolve => setTimeout(resolve, 3000)) // await式の評価が終わってから実行される console.log("2")

Slide 26

Slide 26 text

Object.hasOwn() Object.hasOwn(オブジェクト,プロパティ) オブジェクトが指定のプロパティを持っているかを真偽値で返す。 class Hoge { hige = 1; } const hoge = new Hoge(); console.log(Object.hasOwn(hoge, "hige")) // true が返される 参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn

Slide 27

Slide 27 text

(復習) RegExp Named Capture Groups ES2018から正規表現で?<グループ名>とすることで、マッチした部分にグルー プ名をつけることが出来るようになった。 const regrex = /好きな食べ物は(?.*)です/; const hoge = '好きな食べ物は焼肉 🍖です。'.match(regrex); // グループ名でマッチした部分を取得できる console.log(hoge.groups.favFood) // 焼肉🍖が出力される 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Backreferences

Slide 28

Slide 28 text

RegExp Match Indices 正規表現にdフラグを付けることで、indicesプロパティでマッチした文字列の開 始・終了位置を取得できる。 indices:[開始位置, 終了位置]のように配列形式で格納される。 const regrex = /好きな食べ物は(?.*)です/d; const hoge = '好きな食べ物は焼肉 🍖です。'.match(regrex); console.log(hoge.indices.groups.favFood) // 焼肉🍖の開始・終了インデックスである [7,11]が出力される 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

Slide 29

Slide 29 text

Error Cause エラーが連鎖した場合に、そのエラーの親となるエラーを.causeで辿れる。 親子関係のあるコードで、エラーの発生源を辿るのに便利。 try{ try{ try{ throw new Error('Error1' ); } catch(e){ throw new Error('Error2' , {cause: e}); } }catch(e){ throw new Error('Error3' , {cause: e}); } }catch(e){ console .log(e); // Error3 console .log(e.cause); // Error2 console .log(e.cause.cause); // Error1 } 参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

Slide 30

Slide 30 text

Class Static Block JavaScriptでstaticイニシャライザーが使えるようになった。 staticイニシャライザ―ではクラスが読み込まれた時に一度だけ実行される。 staticイニシャライザーが実行されるタイミングでは、インスタンス化されてい ないので、staticではないフィールドに値を入れることはできない。 class Foo{ static x = 1; static { this.x = 2; console .log("Static initilizer" ); } } console.log(Foo.x); // 2が出力される 参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_static_initialization_blocks