UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【JavaScript】ES2022の仕様

いまさらながらES2022でのアップデートをキャッチアップした

鹿野さんの記事が参考になった   zenn.dev

  • クラスフィールド宣言
  • プライベートなメンバー
  • instanceofの代わりのin
  • トップレベルawait
  • 配列の最後の要素を取得できるat()
  • hasOwnPropertyの代わりのObject.hasOwn()
  • staticイニシャライザー
  • エラーをチェインできる Error.cause
  • 正規表現のdフラグ

詳しくは記事に書かれているので、個人的に覚えておきたいやつだけ tc39 を読む

トップレベルawait

github.com

従来はawaitを使うにはasyncが必要で、すぐに呼び出したい時は以下のように書いていた

// awaiting.mjs
import { process } from "./some-module.mjs";
let output;
(async () => {
  const dynamic = await import(computedModuleSpecifier);
  const data = await fetch(url);
  output = process(dynamic.default, data);
})();
export { output };

ただこれだと、このファイルをimportした側のモジュールはタイミングによっては output に値があるときもあれば、まだundefined のときもあったりして制御が難しい

この問題を解決するためにトップレベルawaitが提案された

// awaiting.mjs
import { process } from "./some-module.mjs";
const dynamic = import(computedModuleSpecifier);
const data = fetch(url);
export const output = process((await dynamic).default, await data);

これにより、呼び出し側はawaiting.mjsawaitが解決されるまでは実行されない

// usage.mjs
import { output } from "./awaiting.mjs";
export function outputPlusValue(value) { return output + value }

console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100), 1000);

これにより output の状態(promissの解決状態)を気にする必要がなくなった

この仕組みは詳しくは以下の記事で理解した

top-level awaitがどのようにES Modulesに影響するのか完全に理解する - Qiita

Error Cause

github.com

特段に何もしなければ、JavaScriptのエラー情報はチェーンせず途絶えてしまう

catch(error) {
  throw new Error("message");  // errorの情報が消える
}

そこで、私は以下のような拡張したクラスを用意していた

class RunError extends BaseError {
  constructor(message, cause) {
    super(message);
    this.cause = cause;
  }
}

【JavaScript】Error を拡張する - UGA Boxxx

これが仕様でシンプルに書けるようになった

catch(error) {
  throw new Error("message", { cause: error });  // errorの情報が消えない
}