JavaScriptの仕様策定を行う TC39 において、2025年に「Finished(完了)」ステータスとなったプロポーザルが ES2026 として登場します。主要ブラウザでの実装が進んでいるこれらの新機能は、開発における「痒い所に手が届かない」課題を解決する強力なツール群です。本記事では、ES2026で追加された主要な新機能をコード例とともに紹介します。
概要と技術的背景
JavaScript(ECMAScript)の進化は、TC39 会合での議論を経て決定されます。ES2026では、データの正確なパース、Map操作の効率化、バイナリデータの扱い、そして非同期イテレータのサポート強化が大きな柱となっています。特に JSON.parse の拡張や Uint8Array のBase64対応は、長年外部ライブラリや複雑な実装に頼っていた部分を標準機能としてカバーする重要なアップデートです。
詳細解説
今回のアップデートで注目すべきは、データ精度の維持とセキュリティ(信頼性)の向上です。
- JSON.parse source text access:
BigInt級の巨大な数値などを扱う際、従来のパースでは精度が失われる問題がありました。新仕様ではreviver関数の第3引数contextを通じて元の生文字列(source)にアクセス可能になり、正確な値を維持できます。 - Map.prototype.getOrInsert: 通称 Upsert と呼ばれる機能です。キーが存在すれば取得し、なければ挿入するという操作を1つのメソッドで行えます。なお、これは
Map専用のメソッドであり、プレーンなオブジェクトには利用できません(オブジェクトには従来通り??=等を使用します)。 - Math.sumPrecise: 浮動小数点の計算において、極端に大きな値と小さな値を加算した際に生じる「情報落ち」を最小限に抑え、可能な限り正確な合計値を算出します。
- Error.isError:
instanceof Errorはクロスレルム(iframe間など)で判定に失敗したり、プロトタイプの偽造が可能だったりという課題がありました。Array.isArray同様、そのオブジェクトが「真のエラー」かどうかを確実に判定します。
エンジニアMath.sumPrecise のおかげで、[1e20, 1, -1e20] のような配列の計算も情報落ちを気にせず 1 と算出できますね。ただし、0.1 + 0.2 のような丸め誤差には効果がない点には注意が必要です。
デザイナーUint8Array がBase64やHexを直接扱えるようになると、画像データやバイナリデータの処理がシンプルになり、パフォーマンス改善も期待できそうです。
実装・利用例
以下に主要な新機能の実装例を示します。
1. JSON.parse source text access
const tooBigInt = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001";
// 第3引数 context.source から変換前の生文字列を取得可能
const result = JSON.parse(tooBigInt, (key, val, context) => {
if (key === "") return val; // トップレベル
return context.source;
});
console.log(result); // "100000...1" (精度を失わずに回収可能)
2. Map.prototype.getOrInsert
let map = new Map([["foo", 1], ["bar", 2]]);
// キーがなければ挿入、あれば既存の値を返す
map.getOrInsert("baz", 3);
map.getOrInsert("foo", 4); // fooは1のまま(上書きされない)
console.log(map.get("baz")); // 3
console.log(map.get("foo")); // 1
3. Math.sumPrecise
let values = [1e20, 1, -1e20];
console.log(values.reduce((a, b) => a + b, 0)); // 0 (情報落ちが発生)
console.log(Math.sumPrecise(values)); // 1 (正確に計算)
// ※丸め誤差には非対応
console.log(Math.sumPrecise([0.1, 0.2])); // 0.30000000000000004
4. Error.isError
let realError = new Error();
let fakeError = new Map();
fakeError.__proto__ = Error.prototype;
console.log(fakeError instanceof Error); // true (偽造可能)
console.log(Error.isError(realError)); // true
console.log(Error.isError(fakeError)); // false (確実に見抜ける)
5. Iterator Sequencing (Iterator.concat)
let lows = Iterator.from([0, 1, 2]);
let highs = Iterator.from([6, 7, 8]);
// 複数のイテレータや配列を直列に連結
let digits = Iterator.concat(lows, [3, 4, 5], highs);
// digitsを配列に変換すると [0, 1, 2, 3, 4, 5, 6, 7, 8]
6. Uint8Array to/from Base64 & Hex
const arr = new Uint8Array([72, 101, 108, 108, 111]);
// Base64変換
const base64 = arr.toBase64(); // "SGVsbG8="
const backFromBase64 = Uint8Array.fromBase64(base64);
// Hex(16進数)変換
const hex = arr.toHex(); // "48656c6c6f"
const backFromHex = Uint8Array.fromHex(hex);
7. Array.fromAsync
async function* asyncGen(n) {
for (let i = 0; i < n; i++) yield i * 2;
}
// 従来の Array.from は非同期イテレータを扱えず [] を返すが、
// fromAsync は Promise を返し、解決後に配列を生成する
const arr = await Array.fromAsync(asyncGen(4)); // [0, 2, 4, 6]
まとめ
- JSON.parse の拡張(sourceアクセス)により、数値精度の問題やパース過程の柔軟性が大幅に向上しました。
- Map.getOrInsert や Iterator.concat により、コレクション操作の記述がより宣言的かつ簡潔になりました。
- Uint8Array のBase64/Hex対応、および Array.fromAsync により、バイナリデータや非同期ストリームの処理が標準機能だけで完結するようになりました。
- Error.isError や Math.sumPrecise は、エッジケースにおける堅牢性と精度の向上に寄与します。