2020-07 の TC39 meeting
まとめ
決まったこと
Web compatibility issues / Needs Consensus PRs
retroactive consensus on Unicode 13 property names and aliases (#1896, #1939) | Michael Ficarra Unicode 13 のための仕様アップデート。承認された。
Specify \8 and \9 in sloppy (non-template) strings (#2054) | Ross Kirsling Sloppy モードにおいて "\8" や "\9" が単に "8", "9" として扱われるが、JavaScriptCore では SyntaxError になっている。そのため仕様にこれを許容することを明記する提案。承認された。
adding Reflect Symbol.toStringTag #2057 | Jordan Harband Reflect[Symbol.toStringTag] が定義されていなかったので定義する話。承認された。
Should eval?.() be direct eval? (#2062, #2063) | Ross Kirsling eval にはダイレクトに実行するとその実行したスコープを、間接的に実行するとグルーバルスコープで実行されるという仕様がある。eval?.() として実行したときにどうするか。仕様に触らずに indirect eval と同じ扱いになった。
歴史的な経緯から Sloppy モードにおいては Legacy Octal Literal を使用することができる。数値のリテラルで先頭に 0 を付け、各桁が8未満の場合に8進数として扱われる。
code: (js)
012 // 10
089 // 89
01.2 // Syntax Error
08.9 // 888.888
01e2 // Syntax Error
08e9 // 8000000000
さてこの Legacy Octal Literal で小数点や exponent パーツを使った場合に Numeric Separator を使うことを許すかどうかという話。特に拒絶することなくそのまま許すことになった。
HTML の仕様によると非同期に呼ばれる函数は Incumbent settings object とよなれる状態に関連付けられている。このオブジェクトは Promise#then のようにジョブのスケジューリングをする API に渡されたときに保存され、コールバックが実行されるときに復元される。
このことを ECMAScript 側の仕様にも記述する提案。承認された。
Intl.NumberFormat の maximumFractionDigits オプションの扱いについての修正。承認された。
code: (js)
Object.defineProperty(this, "x", {
configure: true,
value: 1,
});
(() => {
"use strict";
x = (delete global.x, 2);
})();
というコードがあったとき、仕様によると特にエラーを投げないが、実態としてすべての実装で ReferenceError を投げている。この実態に合わせるために SetMutableBinding を修正する提案。承認された。
ビルトイン函数の Function#toString() による結果が実装によって異なっている。仕様側で正規化する提案。承認された。
Stage 4 (ES2021)
Stage 4 になった 🎉
Stage 4 になった 🎉
Stage 4 になった 🎉
WeakRef と FinalizationRegistory が Stage 4 となり、FinalizationRegisyory#cleanupSome が Stage 2 になった 🎉
Stage 4 になった 🎉
Stage 4 になった 🎉
Stage 3
文字列を word や grapheme 単位などで分割できる提案。
Stage 3 になった。
Stage 2
Decorators が満たすべき成約について話された。
インスタンスに特定の Private Fields が定義されているかどうかを調べるシンタックスを入れる提案。先送りになった。
次の9月の会議までに最後の仕様レビューをしてもらいい、11月に Stage 3 を目標にしていることが話された。
Import Attributes として進んでいた提案が Import Conditions になったらしい。
code: (js)
import o from "./o.json" if { type: "json" };
もろもろを再考することになり、Stage 3 にはならなかった。
引数に insert と update のメソッドを持つオブジェクトを入れる形になった。
code: (js)
// given counts is a Map of object => id
counts.emplace(key, {
insert(key, map) {
return 0;
},
update(existing, key, map) {
return existing + 1;
}
});
型としてはこんな感じかな。
code: (ts)
declare class Map<K, V> {
emplace(key: K, callbacks: {
insert(key: K, map: Map<K, V>): V,
update(existing: V, key: K, map: Map<K, V>): V,
}): void
}
Firefox にだいたいの実装が入ったらしい。Stage 3 のレビューが開始された。
配列などで負数インデックスでも取得できるメソッドを追加する提案。
Stage 2 になった。
第三引数で新たに inclusive かどうかが指定できるようになった。
code: (js)
Number.range(0, 5, 10);
Number.range(0, 5, { step: 10 });
Number.renge(0, 5, { inclusive: true }); // 0, 1, 2, 3, 4, 5
Iterator を返すべきか Iterable を返すべきかや、また Number のスタティックメソッドとして定義するか新たに Number.Range クラスとして定義するかが話題になっている。
時間切れで Stage 2 にはならなかった。
新たに Record/Tuple を導入する提案。永続データ型。
前回の issues が解決し、Stage 2 になった。
Stage 2 になった。
Stage 1
クラス構文に Static Blocks を追加する提案。
code: (js)
class C {
static {
// statements...
}
}
仕様のテキストができたが Stage 2 にはならなかった。
arr[start:end] というシンタックスで arr[Symbol.slice](start, end) と同じ意味になるシンタックスシュガー。今のところ Array, %TypedArray%, ArrayBuffer そして SharedArrayBuffer のプロトタイプに @@slice なメソッドを定義するとのこと。
Array#slice では負数インデックスも対応しているが、普通にブラケットで配列にアクセスしたときには対応していない。新たに Slice notation シンタックスを導入するにあたってそのあたりがややこしくなるという懸念が話された。
Stage 2 にはならなかった。
await に新しく演算子を追加することで書きやすくするシンタックスシュガー。
code: (js)
await.all expr // Promise.all(expr)
await.race expr // Promise.race(expr)
await.allSettled expr // Promise.allSettled(expr)
await.any expr // Promise.any(expr)
Stage 1 になった。
配列からユニークなものだけを集めたいときに [...new Set(arr)] のようなイディオムを使うことになるが、Array#unique として定義する提案。
また引数に key を入れることで配列の中身でも扱えるようになるらしい。
code: (js)
arr.unique("key");
arr.unique(Symbol.for("key"));
他にも函数を入れるとその結果によってユニークかどうかを判定してくれる。
code: (js)
arr.unique((val) => val.toJSON());
ちょっと盛り沢山すぎる提案な気がする……。Stage 1 になった。
WeakMap の key として Symbol を許容する提案。ユースケースやモチベーションを再確認することになり、Stage 2 にはならなかった。
Stage 0
Wasm では export する Identifier Name は UTF-8 の文字列なら何でもよく、JavaScript とは異なるものとなっている。そこで import/export 文でそれらに対応する提案。
code: (js)
import {"@foo" as foo} from "wasm";
export {foo as "@foo"};
export {"@bar" as bar} from "wasm";
承認されたが提案プロセスとは別の形で取り込むことになった。
Zone.js のように非同期なタスクの中でタスクごとに別れたコンテキストを作ることができる API の提案。
code: (js)
const asyncLocal = new AsyncLocal(
(newValue, prevValue) =>
console.log(valueChanged: newValue(${newValue}), prevValue(${prevValue}))
);
async function run() {
// (1)
asyncLocal.setValue('foo');
await sleep(1000);
await next(asyncLocal);
// (3)
asyncLocal.setValue('quz');
}
async function next() {
// (2)
asyncLocal.setValue('bar');
await sleep(1000);
}
// Evaluate the run function twice asynchronously.
Promise.resolve().then(run);
Promise.resolve().then(run);
code: output
// (1)
valueChanged: newValue('foo'), prevValue(undefined);
valueChanged: newValue('foo'), prevValue(undefined);
// (2)
valueChanged: newValue('bar'), prevValue('foo');
valueChanged: newValue('bar'), prevValue('foo');
// (3)
valueChanged: newValue('quz'), prevValue('bar');
valueChanged: newValue('quz'), prevValue('bar');
Stage 1 にはならなかった。
今のところ ECMAScript には ArrayBuffer のサイズを変えるような API は用意されていないが、WebAssembly.Memory には用意されている状態になっている。それによると WebAssembly.Memory#grow によって WebAssembly.Memory#buffer が指すゲッターの ArrayBuffer が変わるような仕様になっている。そのため変更のたびに参照を新しくしないといけない。
code: (js)
// The backing buffer gets detached on every grow in wasm!
let U8 = new Uint8Array(WebAssembly.Memory.buffer);
function derefPointerIntoWasmMemory(idx) {
// Do we need to re-create U8 because memory grew,
// causing the old buffer to detach?
if (U8.length === 0) {
U8 = new Uint8Array(WebAssembly.Memory.buffer);
}
}
この問題を解決するために ResizableArrayBuffer や GrowableSharedArrayBuffer を用意する提案。
Stage 1 になった。
その他
総括
今回は多くの提案が Stage 4 になった。そして今回から議事録に要約がのせられるようになってありがたい。