ECMAScriptの最新動向 2021年11月版
Published on
※ 旧タイトル: TC39 meeting 86th の概要とステージの移動
TC39 の 86 回目のミーティングが 10/25 ~ 10/28 に開催されました。 このミーティングで議題に上がった提案と、そのステージの移動について紹介します。
for Stage 4
Error Cause
Stage 4 になりました。ECMAScript 2022 に入ります
Error Cause は、Error
コンストラクタの第 2 引数に cause
という値で原因となったエラーを渡すことができるようにする提案です。
キャッチする側では、error.cause
で、そのエラーを取得できます。
例を示します。
doUploadJob
関数は fetch
を実行して失敗したときに新しいエラーをスローします。そのエラーの第 2 引数に { cause: err }
というオブジェクトを渡しています。
async function doUploadJob() {
await fetch("https://example.com/upload").catch((err) => {
throw new Error("Upload job result failed", { cause: err });
});
}
try {
await doJob();
} catch (e) {
console.log(e);
console.log("Caused by", e.cause);
}
// Error: Upload job result failed
// Caused by TypeError: Failed to fetch
doUploadJob
がスローしているエラーメッセージは "Upload job result failed"
ですが、その原因となったエラーを cause
として渡すことで、キャッチする側でどのエラーが原因で失敗したのかを取得できます。
この例では、doUploadJob
が失敗した原因が TypeError: Failed to fetch
であったことがわかります。
for Stage 3
今回は、for Stage 3 の提案はありませんでした。
for Stage 2
Array Grouping
Stage 2 になりました
Array Grouping は、Array
に groupBy
というインスタンスメソッドを追加する提案です。
ユースケースはLodash の groupBy
と同様です。
const array = [1, 2, 3, 4, 5];
array.groupBy((i) => {
return i % 2 === 0 ? "even" : "odd";
});
// => { odd: [1, 3, 5], even: [2, 4] }
Partial Application
Stage 2 になりませんでした
Partial Application は、関数の部分適用のための構文を導入します。
例を示します。
add
は 2 つの引数を受け取り、その 2 つを足し合わせて返すだけの単純な関数です。
そして、Partial Application を使って addOne
という新しい関数を作っています。addOne
は、1 つの引数を受け取り、それに1
を足して返す関数です。
つまり、既存の関数の一部の引数だけ渡して、残りの引数を受け取るような関数を作ることができます。
const add = (x, y) => x + y;
const addOne = add~(1, ?);
addOne(2); // 3
現在の JavaScript で表現すると、次のようになります。
const add = (x) => (y) => x + y;
const addOne = add(1);
addOne(2); // 3
Haskell のような関数型プログラミング言語では標準で備わっている機能です。
for Stage 1
String.cooked
Stage 1 になりました
String.cooked
は String
に新しいスタティックメソッド cooked
を追加する提案です。
String.cooked
は String.raw
と逆のことをします。
String.raw`mmm ... \u0064elicious cooked string`;
// mmm ... \u0064elicious cooked string
String.cooked`mmm ... \u0064elicious cooked string`;
// "mmm ... delicious cooked string"
つまり、通常のテンプレートリテラルとおなじ挙動です。
`mmm ... \u0064elicious cooked string`;
// "mmm ... delicious cooked string"
この機能がタグ付きテンプレートリテラルとして存在することで、これを用いて新しいタグ付きテンプレートリテラルを作るときに役にたちます。
function myTag(strings, ...values) {
return String.cooked(strings, ...values.map(value => String(value).toUpperCase())
}
myTag`hello ${'world'}` // "hello WORLD"
Destructure Private Fields
Stage 1 を飛ばして、Stage 2 になりました
Destructure Private Fields は、プライベートフィールドの分割代入のための構文を導入します。
#
からはじまる識別子は通常であれば存在できないので、別の名前にリネームする必要があります。次の例では this.#x
を x
という名前にリネームしています。
class Foo {
#x = 1;
constructor() {
console.log(this.#x); // => 1
const { #x: x } = this;
console.log(x); // => 1
}
}
Bind-this operator
Stage 1 になりました
Bind this operator は、Function.prototype.bind と同様の方法で関数をバインドするための二項演算子を導入する提案です。
以前から存在する Stage 0 の Bind Operator の後継であり、Stage 1 の Extensions の競合です。
Object.prototype.hasOwnProperty.call({ foo: "foo" }, "foo"); // true
({ foo: "foo" }::Object.prototype.hasOwnProperty("foo")); // true
Function helpers
Stage 1 になりませんでした。この提案に含まれる関数は個別の提案として再度提出されるかもしれません。
Function helpers は、Function
のスタティックメソッドとして便利なヘルパー関数を追加する提案です。
Function.flow
は引数に与えられた関数を合成した新しい関数を返します。
const f = Function.flow(f0, f1, f2);
f(5, 7); // f2(f1(f0(5, 7))).
Function.pipe
は第 1 引数の値を、それ移行の引数として渡された関数を合成した関数に渡した結果を返します。
Function.pipe(5, f0, f1, f2); // f2(f1(f0(5))).
Function.constant
は、第 1 引数として渡された値を返し続ける関数を返します。
const f = Function.constant(3);
f("fooo"); // 3
f(3009, 33, 44); // 3
f({ foo: "foo" }); // 3
Function.identifiy
は、第 1 引数に与えられた値をそのまま返します。
Function.identity(3); // 3
Function.identity(4, 5); // 4
Function.tap
はコールバック関数を引数として受け取り、関数を返します。
Function.tape
が返した関数に引数を渡すと、それをコールバック関数に渡して実行し、その上でその引数をそのまま返します。
言葉で説明すると難しいですが、例を見れば簡単だと思います。
const f = Function.tap(console.log);
f(5); // 5 を出力して、5 を返す
Evaluator Attributes
Stage 1 になりました
Evaluator Attributes は、インポートされたモジュールの評価方法を処理系に伝えるための構文を導入します。
例にある通り、提案された目的は WebAssembly のモジュールを JavaScript の Import 文で読み込むためです。しかし、提案の仕様としては WebAssembly には限られていません。
import mod from "./foo.wasm" as "wasm-module";
mod instanceof WebAssembly.Module; // true
現在 Stage 3 の Import Assertions に似ていますが、Import Assertions はモジュールの評価方法に影響を与えることはできません。
RegExp Features
前回のミーティングで提案されたRegExp Featuresが機能ごとに別々の提案に分割されました。
RegExp Modifiers
Stage 1 になりました
RegExp Extended Mode and Comments
Stage 1 になりました
RegExp Atomic Operators
Stage 1 になりませんでした
RegExp \R
Escape
Stage 1 になりました
RegExp Buffer Boundaries
Stage 1 になりました
Updates
ステージの移動はないものの、アップデートがあった提案です。
- Change Array by Copy
- JSON.parse sourct text access
- Records & Tuples
- Explicit Resource Management
- JS Module Blocks
- Array.fromAsync
その他
提案ではなく、仕様書の変更として扱われているものです。
Extending null
合意は得られませんでした
class Foo extends null {}
記事に関する報告などはこちらから