こんにちは!TalentXでMyTalentを開発しているフロントエンドエンジニアの田中です💃
早いもので2026年になってから2ヶ月が経ち、今月冒頭には State of JS 2025 が公開されましたね🎉
本日はState of JS 2025をふまえてES2025で正式採用された注目機能と、開発者が今最も期待しているTC39プロポーザルを紹介しながら、「JavaScriptはどこへ向かおうとしているのか?」を整理していきたいと思います!
1️⃣ ES2025(ECMAScript 2025)で正式採用された機能たち
まずは個人的に魅力的だった利用頻度が比較的多そうな機能をPick Upしてご紹介します!
※ 実際のブラウザでの利用可否等は MDN 等でご確認ください。
✅ Iterator Helpers
配列みたいにイテレーターを直接チェーンできるようになりました!
これ地味にめちゃくちゃ嬉しいやつですね…!
頻繁に使用する.map() や .filter()といったメソッドは、今までは配列のみにしか使用できず、イテレーターで使用するには一度配列に変換しなければこれらのメソッドは使用できませんでした…
// ❌ 今までは一度配列に変換しないといけなかった const posts = [...document.querySelectorAll("li.post")] .values() .filter(item => item.textContent.includes("フロントエンド")); // ⭕️ 直接操作可能に const posts = document.querySelectorAll("li.post") .values() .filter(item => item.textContent.includes("フロントエンド")); // forで反復可能になる for (const post of posts) { console.log(post.textContent); }
中間配列を作らなくて良くなったので、メモリ効率もよくなります。
使えるメソッドは drop, every, filter, find, flatMap, forEach, map, reduce, some, take, toArray が該当します。
✅ Set Methods(集合演算)
集合演算がやってきた!!
個人的にES2025イチオシの機能です🙋
SQLを書いたことがある方なら UNION, INTERSECT, EXCEPT といった集合演算子になじみがありますよね。あの感覚がそのままJSの Set でできるようになりました👏
なぜ Set を使うと速いの? O(n²) → O(n) の話
最近ちょっとバズってた Vercel の react-best-practices にもルールの一部として追加されていました。(js-set-map-lookups)
なぜ Set が推奨されているか少し掘り下げます。
たとえば「配列Aの中で配列Bにも含まれる要素を探す」という処理を考えてみましょう。
const arrayA = ['JavaScript', 'TypeScript', 'HTML', 'CSS']; const arrayB = ['JavaScript', 'Python', 'Go', 'TypeScript']; // ❌ Array.includes() を使ったナイーブな実装:O(n²) const result = arrayA.filter(lang => arrayB.includes(lang)); // filter が n 回まわるたびに includes が m 回探索する → O(n × m) // 要素数が増えるほど計算量が二次的に増加する
arrayB.includes() は毎回先頭から線形探索を行うので、arrayA の要素数を n、arrayB の要素数を m とすると計算量は O(n × m) になります。
つまり、要素数が1000個同士なら最大 100万回の比較が走ることになります🥶
では Set ではどうでしょうか?
Set は内部的にハッシュテーブルで管理されているので、「ある値が含まれているか」のチェックが O(1) で完了します。intersection() は 常に小さい方の Set をなめる*1 仕様なので、全体の計算量は O(min(n,m)) になります。
| 計算量 | |
|---|---|
Array.filter + Array.includes |
O(n × m) |
Set.intersection() |
O(min(n,m)) |
正直なところ、要素数が100 個ほどの配列であればさほど問題になりませんが、配列の比較などはそれなりに実装機会があると思いますので、「配列 × 配列の比較が出てきたら Set に変換する」 と習慣をつけておくとパフォーマンスチューニングのファーストアクションとしてよさそうです😌
const fibonacci = new Set([1, 1, 2, 3 ,5, 8, 13]); const lucas = new Set([2, 1, 3, 4 ,7, 11, 18]); // UNION:和集合(どちらかに含まれる) fibonacci.union(lucas); // → Set {1, 2, 3, 5, 8, …} // INTERSECT:積集合(両方に含まれる) fibonacci.intersection(lucas); // → Set {1, 2, 3}
これまでは自前でループを書いたり、lodashなどのライブラリに頼るしかなかった処理が1行で書けるようになり、ワンライナーでスラスラと書けるのが気持ち良いですね💯
✅ Promise.try()
Promise.try() - JavaScript | MDN
同期・非同期を気にせず、とにかくPromiseに包んで安全に処理できるように!
「この関数が同期か非同期かわからないけど、エラーはちゃんと .catch() で拾いたい」などのよくあるシナリオで活躍します🙌
function riskyOperation() { throw new Error('同期エラー!'); } // ❌ 同期エラーはPromiseチェーンで拾えなかった new Promise(resolve => resolve(riskyOperation())) .then(result => console.log(result)) .catch(error => console.log(error)); // ここに到達しない // ⭕️ Promise.try():同期エラーもPromiseのrejectとして扱ってくれる Promise.try(riskyOperation) .then(result => console.log(result)) .catch(error => console.log(error)) .finally(() => console.log("All settled.")); // たとえばフォームコンポーネントとか type Props = { onSubmit: (data: FormData) => void | boolean | Promise<void | boolean>; } const Form = ({ onSubmit }: Props) => { const handleSubmit = (data: FormData) => { Promise.try(() => onSubmit(data)) .then(() => showSuccessMessage()) .catch((err) => showErrorMessage(err)); }; }
ES2025 まとめ表
ここまででご紹介した機能以外にも、正規表現に使う文字列を安全にエスケープ可能な RegExp.escape() や、JSONファイルをそのままimportできるようになる Import Attributes(with { type: 'json' }) などの機能が追加されています!
| 機能 | 概要 | 使いどころ |
|---|---|---|
| Iterator Helpers | イテレーターを直接チェーン | 大量データの遅延処理 |
| Set Methods | 集合演算メソッド群 | データの絞り込み・比較 |
| Import Attributes | with { type: 'json' } でJSON import |
設定ファイルの読み込み |
| RegExp Duplicate Named Groups | OR内で同じグループ名OK | 複数フォーマットのパース |
| Promise.try() | 同期・非同期を統一的に扱う | エラーハンドリングの簡略化 |
| RegExp.escape() | 正規表現文字列を安全にエスケープ | ユーザー入力の正規表現化 |
| Float16Array | 半精度浮動小数点数配列 | GPU・機械学習系処理 |
2️⃣ 今、最も期待されているプロポーザルについて
開発者が注目しているTC39プロポーザルのランキングがまた面白かったのでこちらも合わせてご紹介します!
TC39 プロポーザルって何?
JavaScript(ECMAScript)の新機能は、TC39 というコミッティが管理する4段階のプロセスを経て正式仕様になります。
| Stage | 意味 |
|---|---|
| 0 | アイデア段階 |
| 1 | 提案として受理、問題領域の探索 |
| 2 | 仕様のドラフトあり、方向性が固まってきた |
| 3 | 仕様ほぼ確定、ブラウザが実装を始める段階 |
| 4 | 正式採用!次のECMAScript仕様に含まれる |
State of JS のアンケートでは「どのプロポーザルに期待してる?」という質問があり、今年は約10,675人が回答しています!
🥇 1位:Temporal(5,614票)
日付地獄からの解放
日付の操作、大変ですよね…😇
Dateオブジェクトはミュータブルだったり、タイムゾーンがUTCとローカルだけだったりと不便が多く、どのプロジェクトでもDay.jsなどのライブラリを使うことが多いと思います。
対しTemporalは「Mathオブジェクトのようなグローバルな名前空間」として実装された、まったく新しい日付・時刻APIです!
Temporal の主な特徴
- 全オブジェクトがイミュータブル
- タイムゾーンをファーストクラスでサポート
- カレンダーシステムに対応(グレゴリオ暦や和暦や中国暦なども◎)
- ナノ秒精度
// ❌ 旧来の Date const date = new Date('2025-04-03'); console.log(date); // 環境によっては「Apr 02」になることもある // ⭕️ Temporal const plainDate = Temporal.PlainDate.from('2025-04-03'); console.log(plainDate.toString()); // 常に "2025-04-03" // タイムゾーンを考慮した現在時刻 const tokyoNow = Temporal.Now.plainDateTimeISO('Asia/Tokyo'); console.log(tokyoNow.toString()); // 例: "2025-04-03T14:30:00.000" // 日付の差分もシンプルに const start = Temporal.PlainDate.from('2025-01-01'); const end = Temporal.PlainDate.from('2025-04-03'); const diff = start.until(end); console.log(diff.days); // 91(日数)
一部ブラウザで実験的実装が進んでおり、実用化が少しずつ現実味をおびてきました! day.js や date-fns の出番が減る日が近いかもしれません…!
🥈 2位:Decorators(3,672票)
@ 記号でクラスをデコレートする、あのやつがついにJS本体に!
TypeScript使いの方にはもうお馴染みの構文ですよね。Angular や NestJS では日常的に使っているはず。それが Stage 3 として TC39 に正式に入ってきました。
Decoratorsは、クラス・メソッド・フィールドにメタデータや振る舞いを付与できる仕組みです。@ を前置するだけで、コードをクリーンに保ちながら機能を追加できます。
// ログを取るデコレーターを定義 function log(target, context) { return function (...args) { console.log(`Calling ${context.name} with`, args); const result = target.apply(this, args); console.log(`Result:`, result); return result; }; } class Calculator { @log add(a, b) { return a + b; } } const calc = new Calculator(); calc.add(1, 2); // → "Calling add with [1, 2]" // → "Result: 3"
BabelとTypeScriptで先行利用可能となっていますが、ブラウザネイティブ実装はまだ進行中です。
🥉 4位:map.getOrInsert()(1,816票)※3位は「該当なし」
※ State of JavaScript 2025アンケート収集時ではプロポーザルでしたが、執筆時点(2026年2月)でなんと全主要ブラウザ対応済みになりました🥳
Map.prototype.getOrInsert() - JavaScript | MDN
「あったら取得、なければ追加」を1行で実装可能に!
たとえば フロントエンド開発者ではおなじみのチュートリアル「Todo アプリの実装」では以下のようにグルーピングの処理を変更できます!
const todos = [ { id: 1, title: '牛乳を買う', status: 'todo' }, { id: 2, title: '資料を作る', status: 'doing' }, { id: 3, title: 'メールを送る', status: 'todo' }, { id: 4, title: 'PRをレビューする', status: 'done' }, { id: 5, title: 'ミーティング', status: 'doing' }, ]; // ❌ 今まで:has → set → get の3ステップが毎回必要 const grouped = new Map(); for (const todo of todos) { if (!grouped.has(todo.status)) { grouped.set(todo.status, []); // なければ初期化 } grouped.get(todo.status).push(todo); // 取得して追加 } // ✅ getOrInsert() を使えば:取得と初期化が同時にできる! const grouped = new Map(); for (const todo of todos) { grouped.getOrInsert(todo.status, []).push(todo); } // どちらも同じ結果 // Map { // 'todo' => [{ id: 1, ... }, { id: 3, ... }], // 'doing' => [{ id: 2, ... }, { id: 5, ... }], // 'done' => [{ id: 4, ... }] // }
ネストが消えて、やりたいことが1行で伝わるコードになりました🎉
また初期値が固定値ではなく、動的に生成したい場合は getOrInsertComputed() が使えます。
Map.prototype.getOrInsertComputed() - JavaScript | MDN
こちらはキーが存在しない場合だけファクトリ関数を実行してくれるので、不要なオブジェクト生成を避けられるのがポイントです💡
// ❌ getOrInsert() だと毎回 [] が生成されてしまう(キーがあっても) grouped.getOrInsert(todo.status, []); // [] は常に評価される // ✅ getOrInsertComputed() ならキーがないときだけ関数を実行 grouped.getOrInsertComputed(todo.status, () => []); // なかったときだけ [] を生成 // APIキャッシュの実装にも最適 const cache = new Map(); async function getUser(id) { // キャッシュになければfetchして格納、あればキャッシュを返す return cache.getOrInsertComputed(id, () => fetchUserFromDB(id)); }
getOrInsert() と getOrInsertComputed() の使い分けはシンプルで、初期値がプリミティブや軽い固定値なら前者、配列・オブジェクトや非同期処理が絡むなら後者といった意識で良さそうです!
上記で紹介した他にもJSONパース時に「元のテキスト」にアクセスできるようになることが期待されていたり*2、ファイルハンドル、DBコネクション、WebSocketといった最後には必ずクリーンアップしたいシーンでキーワード一つで実現できるようになること*3が望まれているといった結果になりました…!
まとめ:JS の未来はどこへ向かう?
ES2025で実装された機能や、State of JS 2025 の New Proposals セクションを見ると、いくつかの方向性が見えてきます👀
① 「つらいところ」を本体で解決していく流れ
Dateの苦痛など、長年サードパーティライブラリで補っていた部分がどんどん標準化されていますね…!
② フレームワーク由来の概念がJS本体へ
Decoratorsは Angular/NestJS 由来、Signals*4 は Vue/Solid 由来のアイデアが言語仕様に取り込まれようとしています。これらの事実からフレームワークが「JS の未来をデザインしている」とも言えそうです。
③ 開発者体験(DX)重視
map.getOrInsert() のような小さな改善も着実に積み重なっています。「冗長だな」「これ毎回書いてる」という定型コードを排除する動きはこれからも続いていきそうです…!
近年のフロントエンド界隈では多くの変化が起こっていますね!実際、「JSの変化についていくのが大変...」というのは多くの開発者の実感のようで、アンケートでも「ほとんどの機能について学んでさえいない」という回答が最多でした🤔
この記事が少しでもお役に立てれば幸いです!!
一緒に働く仲間を募集しています✨
TalentXでは現在新しい仲間を募集中です! talentx.brandmedia.i-myrefer.jp
カジュアル面談も実施しておりますので、ぜひお気軽にご応募ください!
i-myrefer.jp
*1:https://tc39.es/proposal-set-methods/#sec-set.prototype.intersection
*2:5位:JSON.parse Source Text Access New Proposals
*3:6位:Explicit Resource Management New Proposals
*4:13位:Signals New Proposals