TC39 で提案されている ECMAScript 最新仕様 / ECMAScript latest specification proposed in TC39

A4906ea02ea1385bf9a8a18eac62c6da?s=47 森建
August 20, 2019

TC39 で提案されている ECMAScript 最新仕様 / ECMAScript latest specification proposed in TC39

A4906ea02ea1385bf9a8a18eac62c6da?s=128

森建

August 20, 2019
Tweet

Transcript

  1. TC39 で提案されている ECMAScript 最新仕様 pixiv Inc. petamoriken 2019.8.20 #9 FukuokaJS

    LT
  2. 2 自己紹介 • 主にフロントエンドエンジニア • ActionScript 3.0 を JavaScript に書き直したり

    WebGL を駆使したサイトを作ったり PHP のコードをリファクタリングしたり • ECMAScript とか DOM API を追うのが好き petamoriken 課題解決部
  3. 3 Ecma International TC39 とは • JavaScript の言語仕様 ECMAScript を策定する専門委員会

    • 提案一覧は GitHub 上で管理されている ◦ https://github.com/tc39/proposals • だいたい2ヶ月おきに会議を開いている ◦ アジェンダ: https://github.com/tc39/agendas ◦ 議事録: https://github.com/rwaldron/tc39-notes
  4. 4 ECMAScript の策定プロセス • Stage 1 Proposal ◦ 担当者が決まる •

    Stage 2 Draft ◦ 最初の Spec テキストが作られる • Stage 3 Candidate ◦ Spec テキストが完成し、レビューが完了する • Stage 4 Finished ◦ polyfill ではない2つの実装で互換性が確認される
  5. 5 議論に参加するには • 既存の提案については該当のリポジトリの issues へ • 新規提案については ES Discuss

    というメーリングリストへ ◦ ここ数日は Modulo Operators がホットトピック ◦ Float16Array ▪ polyfill 書いたら Stage 1 になった ◦ Map#assign ▪ 提案したらより包括的な Collection Methods が Stage 1 になった
  6. 具体的に各 Stage の提案を 10個ほど紹介していきます 6

  7. Stage 4 (ES2020) 3 out of 3 7

  8. 8 String#matchAll • 正規表現のキャプチャを含めてマッチした文字列を得るメソッド const reg = /t(e)(st(\d?))/g; const str

    = "test1test2"; str.match(reg); // -> ["test1", "test2"] • String#match だとキャプチャ出来ない
  9. 9 String#matchAll • RegExp#exec だとループ処理を書く必要がある let match; while (match =

    reg.exec(str)) { // reg.lastIndex プロパティを書き換えることで状態を保持している console.log(match); } // -> ["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined] // -> ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined]
  10. 10 String#matchAll • String#matchAll を使うと安全に得られる for (const match of str.matchAll(reg))

    { // Iteratorの内部で状態を保持している(RegExp#execよりも安全) console.log(match); } // -> ["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined] // -> ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined]
  11. 11 Dynamic Imports • 動的にモジュールを読み込むことができるシンタックス • 読み込みに成功したら以降その結果をキャッシュする • 読み込み失敗時にはキャッシュされない ◦

    ちょうど一昨日その変更が入った Normative: change idempotency for HostImportModuleDynamically https://github.com/tc39/ecma262/pull/1645
  12. 12 Promise.allSettled • Promise が全て fullfilled か rejected のときに fullfilled

    する Promise を返すスタ ティックメソッド • Promise.all は ◦ Promise が全て fullfilled のときに fullfilled ◦ Promise が1つでも rejected のときに rejected
  13. Stage 3 3 out of 14 13

  14. 14 Weak References let obj = { foo: "foo" };

    const weakRef = new WeakRef(obj); console.log(weakRef.deref()); // -> { foo: "foo" } // { foo: "foo" } への参照をなくす obj = null; // しばらく経って GC によって回収されたら null になる console.log(weakRef.deref()); // -> null
  15. 15 Weak References • GC された後処理用のコールバックを登録出来る const finalization = new

    FinalizationGroup((holdings) => { for (const holding of holdings) { console.log(holding); // -> "bar" } }); // コールバックに渡す引数とともに登録する finalization.register(obj, "bar");
  16. 16 Weak References • GC は実装によって挙動が異なるためロジックとして扱うことは非推奨 ◦ GC の順番保証はされず、タイミングを制御することは出来ない ◦

    ブラウザでタブを閉じたときに後処理用のコールバックは実行されない ◦ 例えば GC されたら Local Storage などに退避させて、また必要になったら取り出す などの処理はバグる恐れがあるのでしてはいけない • あくまで過剰なメモリ使用を削減したり、メモリリークを防ぐなどのために使うことを推奨して いる
  17. 17 Nullish Coalescing Operators • 主にオプションのデフォルト値周りが書きやすくなる演算子 interface Options { width?:

    number; height?: number; duration?: number; } const options: Options = { width: 100, duration: 0, };
  18. 18 Nullish Coalescing Operators • null, undefined のときにデフォルト値を受け取るようにする const width

    = options.width != null ? options.width : 256; const height = options.height != null ? options.height : 256; const duration = options.duration != null ? options.duration : 500; • Nullish Coalescing Operators で書きやすくなる const width = options.width ?? 256; const height = options.height ?? 256; const duration = options.duration ?? 500;
  19. 19 Optional Chaining • オプション自体が null の場合に対処しやすくなる interface Options {

    width?: number; height?: number; duration?: number; } const options: Options | null = null;
  20. 20 Optional Chaining • オプション自体が null の場合を考慮しないと TypeError を引き起こす const

    width = options.width ?? 256; // Uncaught TypeError: Cannot read property 'width' of null • Optional Chaining で null, undefined に対処する const width = options?.width ?? 256; const height = options?.height ?? 256; const duration = options?.duration ?? 500;
  21. Stage 2 3 out of 17 21

  22. 22 Decorators • クラスやメソッドに @foo などを付与することで処理を追加するシンタックス • 最新仕様は今年3月に登場した3代目 Built-in Decorators

    ◦ TypeScript の experimentalDecorators は初代の仕様のままで全然追随出来てい ない ◦ Babel は2代目の仕様のまま • 詳しくは Qiita の ESNext Stage 2 Decorators の変遷と最新仕様 という記事へ
  23. 23 Iterator Helpers • Iterator/AsyncIterator を変換・操作するメソッド • 遅延評価のため Array から

    Array を作るよりも無駄にならない ◦ next メソッドで値を取り出すときに処理がなされる • 詳しくは uhyo さんの JavaScriptのイテレータが持つメソッドをそろそろ知っておきたい人 が読む記事 へ const iterator = [1, 2, 3, 4, 5].values(); const array = iterator.take(3) .map((value) => value * 2) .toArray();
  24. 24 Explicit Resource Managements • 明示的にリソースの後処理をするシンタックス • 具体的なシンタックスについてはまだ未定 try (const

    fileHandle = acquireFileHandle()) { // スコープを抜けるときに // fileHandle[Symbol.dispose] が呼ばれ開放処理を行う } • 詳しくは uhyo さんの try-using文を用いるJavaScriptの超モダンな“リソース管理” へ
  25. Stage 1 1 out of 48 25

  26. 26 Emitter • 今年6月に登場した期待(?)の新人 • Push-based Streams を扱えるインターフェースとして提案されている const emitter

    = new Emitter(); emitter.each((value) => console.log(value)); // -> 42 emitter.next(42);
  27. 27 Emitter • EventTarget から Emitter を作る Emitter.run( Emitter.on(document, "click"),

    Emitter.filter((e) => e.target.tagName === "BUTTON"), Emitter.map((e) => ({ x: e.clientX, y: e.clientY })), (coords) => console.log(coords), );
  28. 28 Emitter • Stage 1 Observable (RxJS) vs Emitter ◦

    どちらも Push-based Streams を扱える ◦ Observable は Subscription と双方向にやりとりするが Emitter は単方向 のみ ▪ RxJS で言うところの Hot な状態のみを扱える ▪ つまり Emitter は Observable よりも扱える領域は狭いと言える
  29. 29 Emitter • Iterable, AsyncIterable (Pull-based Streams), Promise も幅広く扱うことが出来る •

    Emitter を経由して Iterable から Array を作る ◦ Emitter.reduce でコレクションに変換できる const iterator = [1, 2, 3, 4, 5].values(); const array = Emitter.run( iterator, Emitter.until(3), Emitter.map((value) => value * 2), Emitter.reduce([]), );
  30. 30

  31. 31 Emitter • まだ Stage 1 なのでよくわからないが現段階で API が結構やばめ •

    引数の型によって動作が変わる ◦ Emitter.reduce(0) は number が流れてきたら足し、それ以外だと 1足す ◦ Emitter.reduce("") は流れてきたものを string にキャストし連結する ◦ Emitter.reduce([]) は流れてきたものを Array#push する ◦ Emitter.reduce({}) は流れてきたものを Object.assign する • もし非同期のものが流れてきた場合はどうなるんだろう ……
  32. 32 終わりに • みなさんも TC39 の動向を追ってみてはいかがでしょうか? • 個人的に Scrapbox に

    TC39 meeting を日本語でまとめているのでよければどうぞ