とほほのES2025入門

目次

ES2025とは

JavaScript の標準仕様 ES2025 (ECMAScript 16th Edision) として 2025年6月にリリースされる予定です。新たに追加される予定の機能について説明していきます。

ES2025強化項目

RegExp Modifiers

正規表現で i, m, s などのフラグは /.../ の後ろに記述して正規表現全体に対して機能していました。例えば下記の例ではすべての文字が i フラグにより大文字・小文字が無視されます。

"ab".match(/^AB$/i)        // 大文字・小文字を無視するので true

正規表現の一部にだけフラグを適用するために、(?flag:exp) の書式がサポートされます。

"AB".match(/^A(?i:B)$/)    // Aは大文字ですが、Bが大文字・小文字が無視されます

(?-flag:exp) はグローバルに指定したフラグを一部だけ解除します。

"AB".match(/^A(?-i:B)$/i)  // 全体としては大文字・小文字を無視しますが、B だけは大文字

RegExp.escape()

RegExp.escape(str)str に含まれる正規表現のメタ文字を無効化します。具体的には、空白文字、アンダースコア(_)を除く記号文字、および、安全のため最初の1文字をエスケープします。エスケープは - を \x2d の様に16進数にエスケープするものと、$ を \$ のように \ を付与してエスケープするものがあります。

RegExp.escape("Are you OK?")     // "\x41re\x20you\x20OK\?"

Duplicate named capturing groups

正規表現で名前付きキャプチャグループを使用する際、同じ名前が複数回出現するとエラーになっていましたが、複数回書けるようになります。年-月 にも 月-年 にも対応する正規表現を下記の様に記述できます。

const str = "06-2025";
const ret = str.match(/(?<year>[0-9]{4})-(?<month>[0-9]{2})|(?<month>[0-9]{2})-(?<year>[0-9]{4})/);
console.log(ret.groups.year);
console.log(ret.groups.month);

New Set methods

Set に下記のメソッドが追加されます。

const A = new Set([1, 2, 3]);
const B = new Set([3, 4, 5]);
console.log(A.intersection(B));        // AにもBにも含まれるもの [3]
console.log(A.union(B));               // AまたはBに含まれるもの [1, 2, 3, 4, 5]
console.log(A.difference(B));          // Aの内Bにに含まれないもの [1, 2]
console.log(A.symmetricDifference(B)); // AまたはBどちらか片方のみに含まれるもの [1, 2, 4, 5]
console.log(A.isSubsetOf(B));          // AがBの部分集合であれば true
console.log(A.isSupersetOf(B));        // AがBのスーパーセット(BがAの部分集合)であれば true
console.log(A.isDisjointFrom(B));      // AとBに共通項が無ければ true

Sync Iterator helpers

ジェネレーター を用いて反復可能オブジェクトを生成することができます(既存機能)。

function* myRange(n, m) {
  while (n <= m) {
    yield n++;
  }
}
for (var n of myRange(1, 5)) {
  console.log(n);         // 1, 2, 3, 4, 5
}

この反復可能オブジェクトに下記のようなヘルパーメソッドが追加されます。

// それぞれの要素に関数を実行した反復可能オブジェクトを返す
for (var n of myRange(1, 5).map(value => value * 2)) {
  console.log(n);         // 2, 4, 6, 8, 10
}

// 関数の結果が true となる要素からな反復可能オブジェクトを返す
for (var n of myRange(1, 5).filter(value => value % 2 == 0)) {
  console.log(n);         // 2, 4
}

// 最初の3個のみを抽出した反復可能オブジェクトを返す
for (var n of myRange(1, 5).take(3)) {
  console.log(n);         // 1, 2, 3
}

// 最初の3個を読み飛ばした反復可能オブジェクトを返す
for (var n of myRange(1, 5).drop(3)) {
  console.log(n);         // 4, 5
}

// それぞれの要素に関数を実行した結果をフラットにした反復可能オブジェクトを返す
for (var n of myRange(1, 5).flatMap(value => [value, value + 0.5])) {
  console.log(n);         // 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5
}

// それぞれの要素に対して逐次的に関数を実行し、その最終結果を返す
console.log(
  myRange(1, 5).reduce((sum, value) => sum + value) // 15
);

// 反復可能オブジェクトを配列に変換する
console.log(
  myRange(1, 5).toArray() // [1, 2, 3, 4, 5]
);

// forEach() でループ処理する
myRange(1, 5).forEach((n) => {
  console.log(n)          // 1, 2, 3, 4, 5
});

// それぞれの要素に関数を実行した結果がひとつでも true であれば true
console.log(
  myRange(1, 5).some(v => v == 3)    // true
);

// それぞれの要素に関数を実行した結果がすべて true であれば true
console.log(
  myRange(1, 5).every(v => v < 10)   // true
);

// それぞれの要素に関数を実行して true となった個数を返す
console.log(
  myRange(1, 5).find(v => v >= 3)    // 3
);

また、Iterator.from() を用いてイテレーターを反復可能オブジェクトに変換することが可能となります。

class MyRangeIterator {
  constructor(n, m) {
    this.n = n;
    this.m = m;
  }
  next() {
    return { value: this.n, done: this.n++ > this.m };
  }
}
const iterator = new MyRangeIterator(1, 5);        // イテレーター
const iterable_object = Iterator.from(iterator);   // 反復可能オブジェクト
for (var n of iterable_object) {
  console.log(n);
}

Import Attributes / JSON Modules

CSS, JSON などを import 文で読み込めるようになります。

import json from "./foo.json" with { type: "json" };
import style from "./style.css" with { type: "ccs" };

Promise.try()

Promise.try() は同期関数も非同期関数もまとめて Promise でラッピングします。条件によって Promise を返却したり実データを返却する関数をまとめて Promise に統合することができます。例えば、下記の getData() は引数 url に対応するデータがキャッシュにあれば実データを、無ければ Promise を返却します。呼び出し側も戻り値が Promise か否かで処理を振り分ける必要があります。

const cache = new Map();

function getData(url) {
  if (cache.has(url)) {
    return cache.get(url);
  }
  return fetch(url)
    .then(async (res) => {
      const body = await res.text();
      cache.set(url, body);
      return body;
    });
}

document.getElementById("btn").addEventListener("click", () => {
  const url = document.getElementById("url").value;
  const ret = getData(url);
  if (ret instanceof Promise) {
    ret.then((value) => {
      console.log(value);
    });
  } else {
    console.log(ret);
  }
});

この時、getData()Promise.try() でラッピングしてやることで、キャッシュの有無に関わらず、戻り値を Promise として扱うことができるようになります。

document.getElementById("btn").addEventListener("click", () => {
  const url = document.getElementById("url").value;
  Promise.try(() => getData(url))
    .then((value) => {
      console.log(value);
    });
});

Float16Array

Float16Array がサポートされます。WebGPU や機械学習での利用が期待されます。DataView.prototype.getFloat16() DataView.prototype.setFloat16(), Math.f16round() も追加されます。

const float16 = new Float16Array(2);
float16[0] = 1.23;
float16[1] = 4.56;
console.log(float16[0]);
console.log(float16[1]);