Contents
ES2024 概要と TC39 採択プロセス
ES2024 で標準化された主な機能は次の通りです。
- Array.prototype.findLast / findLastIndex(配列末尾から検索)
- 正規表現に対する Unicode Set 用 v フラグと マッチインデックス の提案(Stage 3 まで進行中)
- 既存機能の利用促進策として、Object.hasOwn(ES2022 で導入)や Promise.any のポリフィル戦略
TC39 の標準化フローは Stage 0 → Stage 4 の 5 段階で管理されます。各段階の要件と、2024 年に最終採択された提案を以下に示します。
| Stage | 主な要件 | ES2024 に組み込まれた提案 |
|---|---|---|
| 0 | アイデア公開・議論開始 | Array.findLast(proposal‑array‑find‑last) |
| 1 | 仕様草稿作成、実装可能性評価 | RegExp v flag & matchIndices(proposal‑regexp‑v‑flag, proposal‑regexp‑match-indices) |
| 2 | 完全な仕様決定+最低 1 実装必須 | Object.hasOwn(既に ES2022 に実装) |
| 3 | 互換性テスト・パフォーマンス評価 | Promise.any の実装状況確認 |
| 4 | 標準化承認 | 上記機能が ECMAScript 2024 に掲載 |
このプロセスは TC39 が公開している公式レポート と完全に一致し、採択された提案は全て「実務で安全に使える」ことが保証されています。
安全な所有プロパティ判定 – Object.hasOwn
背景と位置付け(導入文)
Object.hasOwn は ES2022 で正式に追加された静的メソッドですが、ES2024 のコードベースでも頻繁に登場します。従来の hasOwnProperty がプロトタイプ汚染に弱い点を解消し、安全な所有権チェックを実現します。
Object.hasOwn と hasOwnProperty の比較
| 項目 | obj.hasOwnProperty(key) |
Object.hasOwn(obj, key) |
|---|---|---|
| 呼び出し形態 | インスタンスメソッド(プロトタイプが必要) | 静的メソッド(任意のオブジェクトに適用可能) |
| プロトタイプ汚染耐性 | 低(上書きされるとエラー) | 高(組み込み関数で上書き不可) |
| 戻り値 | true / false |
同左 |
|
1 2 3 4 5 6 7 8 9 |
const user = Object.create({ inherited: true }); user.id = 123; // 従来の安全な書き方 console.log(Object.prototype.hasOwnProperty.call(user, 'id')); // → true // 新しい推奨方法 console.log(Object.hasOwn(user, 'id')); // → true |
実務での置換手順
- 検索・置換
エディタ全体でObject.prototype.hasOwnProperty.call(をObject.hasOwn(に置き換える。 - 型定義の更新(TypeScript)
json
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["DOM", "ES2024"] // ES2024 で最新の宣言ファイルを取得
}
} - Lint ルールの追加
eslint-plugin-unicornのunicorn/prefer-object-has-ownを有効化すると、誤用が検出されます。
配列末尾検索 – Array.findLast / findLastIndex
なぜ配列末尾検索が重要か(導入文)
大規模データやログ解析では「最新の対象」を取得したいケースが多く、先頭から走査する find 系は非効率です。ES2024 で追加された findLast* 系は O(n) の走査を逆方向に行うだけで済むため、コードの可読性とパフォーマンスが同時に向上します。
基本的な使い方
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const logs = [ { level: 'info', msg: '開始' }, { level: 'error', msg: '失敗A' }, { level: 'warn', msg: '警告' }, { level: 'error', msg: '失敗B' } ]; // 末尾から最初の error を取得 const lastError = logs.findLast(entry => entry.level === 'error'); console.log(lastError.msg); // → "失敗B" // インデックスだけが必要な場合 const idx = logs.findLastIndex(entry => entry.level === 'error'); console.log(idx); // → 3 |
実務シナリオ例
| シーン | 目的 | findLast* の利点 |
|---|---|---|
| ログ解析 | 「最新エラー」抽出 | 逆走検索でコードが簡潔に |
| UI 履歴スタック | 最後のユーザー操作取得 | 配列全体を保持したまま高速検索 |
| データストリーム | バッファの最後の有効レコード取得 | 余計なフィルタリング不要 |
Promise.any と Polyfill 戦略
現行ブラウザ実装状況(導入文)
Promise.any は ES2021 に標準化されましたが、古い環境への対応が依然として課題です。以下の表は 2026‑05‑13 時点で主要ブラウザと Node.js の実装ステータスをまとめたものです。
| ブラウザ | 実装バージョン |
|---|---|
| Chrome | 109 以降 ✅ |
| Edge | 109 以降 ✅ |
| Firefox | 115 以降 ✅ |
| Safari | 16.4 以降 ✅ |
| Node.js | v18.0.0 以降 ✅ |
Polyfill の選択肢
- core‑js (
es.promise.any) – 必要なだけ自動的にポリフィリング - promise-any-polyfill – 軽量版だが、
AggregateErrorの互換性に注意
|
1 2 |
npm i -D core-js |
|
1 2 3 4 5 6 7 8 9 |
import 'core-js/es/promise/any'; // 必要な環境だけ polyfill される const p1 = fetch('/api/a'); const p2 = fetch('/api/b'); Promise.any([p1, p2]) .then(res => console.log('最初に成功したレスポンス', res)) .catch(err => console.error('すべて失敗:', err)); |
正規表現の進化 – v フラグとマッチインデックス
現状と採択ステータス(導入文)
ES2024 の正式仕様には v フラグ と matchIndex プロパティ は含まれていません。現在は Stage 3 まで進んだ Unicode Set (v) と、マッチ位置を配列で返す Match Indices (indices) の提案が検討中です。そのため、実装環境ではポリフィルやトランスパイルが必要になります。
| 提案 | 現在のステージ | 主な機能 |
|---|---|---|
RegExp v flag (Unicode Set) |
Stage 3 | 文字クラスを {...} 記法で記述可能にする |
RegExp matchIndices (indices) |
Stage 3 | .indices プロパティでマッチ開始・終了位置を取得 |
実装例(Polyfill 使用)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// regexpu-core で v フラグをトランスパイル import { transform } from 'regexpu-core'; const source = '(?<word>\\p{L}+ )(?<num>\\d+)'; const transformed = transform(source, 'v'); // -> ES2022 相当の正規表現文字列 const re = new RegExp(transformed); const str = '商品123'; const m = re.exec(str); if (m) { console.log(m.groups.word); // 商品 console.log(m.groups.num); // 123 } |
注意:
matchIndexは現在の仕様に存在せず、代わりにresult.indices?.[0](開始位置)やresult.indices?.[1](終了位置)を参照してください。
トップレベル await の現状
既存機能としての位置付け(導入文)
トップレベルでの await は ES2022 にて標準化され、Node.js 20+ やモダンブラウザでも利用可能です。ES2024 ではこの機能が「実務向けに安定した形で広くサポートされることを前提」として言及されています。
|
1 2 3 |
// config.mjs(トップレベル await の例) export const config = await fetch('/config.json').then(r => r.json()); |
上記コードは ビルドツールやバンドラが ESM を正しく解釈できる環境 であれば、追加のラッパー関数なしに非同期初期化を行えます。
実務導入ガイド:対応状況・マイグレーションベストプラクティス
ブラウザ / Node.js の実装ステータス(2026‑05‑13)
| 機能 | Chrome | Edge | Firefox | Safari | Node.js |
|---|---|---|---|---|---|
Object.hasOwn |
115+ ✅ | 115+ ✅ | 115+ ✅ | 16.4+ ✅ | v18 ✅ |
Array.findLast / findLastIndex |
115+ ✅ | 115+ ✅ | 117+ ✅ | 16.4+ ✅ | v20 ✅ |
Promise.any |
109+ ✅ | 109+ ✅ | 115+ ✅ | 16.4+ ✅ | v18 ✅ |
| RegExp v フラグ(提案) | 124* ❓ | 124* ❓ | 123* ❓ | 17.2* ❓ | v20 (experimental) |
| RegExp indices(提案) | 124* ❓ | 124* ❓ | 123* ❓ | 17.2* ❓ | v20 (experimental) |
| Top‑level await | 109+ ✅ | 109+ ✅ | 115+ ✅ | 16.4+ ✅ | v14 (esm) |
*「❓」は実装が 実験的 または フラグ付き のため、プロダクション利用時はポリフィルやトランスパイルが推奨されます。
推奨 Polyfill / トランスパイラ
| 機能 | 推奨ライブラリ |
|---|---|
Object.hasOwn・Array.findLast・Promise.any |
core-js(es.object.has-own, es.array.find-last, es.promise.any) |
| RegExp v フラグ & indices | regexpu-core(コード変換)、regexp-modifiers-polyfill(実装が無い場合の代替) |
ESLint・TypeScript の設定手順
-
ESLint
bash
npm i -D eslint-plugin-unicorn
js
// .eslintrc.js
module.exports = {
extends: ['eslint:recommended', 'plugin:unicorn/recommended'],
plugins: ['unicorn'],
rules: {
'unicorn/prefer-object-has-own': 'error',
'unicorn/prefer-array-find-last': 'error',
// 提案段階の正規表現は警告レベルで管理
'unicorn/no-unsafe-regex': 'warn'
}
}; -
TypeScript
json
{
"compilerOptions": {
"target": "ES2022",
"module": "esnext",
"lib": ["DOM", "ES2024"],
"useDefineForClassFields": true,
"strict": true
}
} -
Babel(ビルドツール)
js
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
targets: '> 0.5%, not dead',
useBuiltIns: 'usage',
corejs: { version: 3, proposals: true }
}]
]
};
実践サンプルコード(Playground 用)
以下のスニペットは ES2024 の主要機能を組み合わせた 実務レベルの例 です。ブラウザコンソールや Node.js REPL に貼り付けるだけで動作確認できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// sample.mjs import 'core-js/es/promise/any'; // Polyfill for older browsers import { transform } from 'regexpu-core'; // v フラグトランスパイル /* 1. 安全な所有プロパティ判定 */ const cfg = { env: 'production' }; if (Object.hasOwn(cfg, 'env')) { console.log('環境設定が存在します'); } /* 2. 配列末尾検索 */ const records = [ { id: 1, status: 'ok' }, { id: 2, status: 'error' }, { id: 3, status: 'ok' } ]; const lastError = records.findLast(r => r.status === 'error'); console.log('最後のエラーレコード ID:', lastError?.id); /* 3. Promise.any の利用(フォールバック付き) */ const apiA = fetch('/api/a').then(r => r.json()); const apiB = fetch('/api/b').then(r => r.json()); Promise.any([apiA, apiB]) .then(data => console.log('取得成功:', data)) .catch(() => console.warn('全 API が失敗しました')); /* 4. 正規表現 v フラグと indices の例(トランスパイル使用) */ const source = '(?<word>\\p{L}+)(?<num>\\d+)'; const transpiled = transform(source, 'v'); // ES2022 相当の文字列へ変換 const re = new RegExp(transpiled); const text = '商品123'; const m = re.exec(text); if (m) { console.log(`単語: ${m.groups.word}, 数字: ${m.groups.num}`); // indices が利用可能ならば以下のように取得 if (m.indices) console.log('マッチ位置:', m.indices[0]); // [開始, 終了] } /* 5. トップレベル await(ESM のみ) */ export const settings = await fetch('/settings.json').then(r => r.json()); console.log('ロードした設定', settings); |
ポイント
-core-jsが自動的に未実装機能をポリフィリングします。
- 正規表現のvフラグは トランスパイル しているため、古いブラウザでも同等の挙動が得られます。
- トップレベル await はモジュール形式(.mjs)でのみ有効です。
まとめ
- ES2024 のコアは配列操作と正規表現の拡張にあり、実務での安全性・可読性向上が期待できます。
Object.hasOwnは ES2022 の機能ですが、ES2024 コードベースでも積極的に採用すべき「標準的な安全チェック」です。- 正規表現の
vフラグとマッチインデックスは 提案段階であり、プロダクションでは polyfill/トランスパイルが必須です。 - ブラウザ実装状況を正確に把握し、必要に応じて core‑js や regexpu-core を組み込むことで、モダンな API を安全に導入できます。
このガイドに沿って設定・コードを書き換えれば、ES2024 の新機能を最大限活用した 堅牢で保守性の高い JavaScript/TypeScript プロジェクトへスムーズに移行できるでしょう。