はじめに
JavaScriptは絶え間ない進化を続けています。これを追いかけていくと、多数の便利な追加や改善の中に、従来のコードが時代遅れになるような、コードの書き方が変わるほどのインパクトある機能を見つけることができます。本連載は、JavaScriptを普段使いする開発者に向けて、JavaScriptの標準規格である「ECMAScript」で標準化された、あるいは標準化予定の機能を紹介しながら、開発者が自身のコードをどうアップデートすべきか解説します。
対象読者
- JavaScriptの最新バージョンの機能を把握したい方
- JavaScriptの経験者で、JavaScriptに改めて入門したい方
- プログラミング言語の最新パラダイムに関心のある方
必要な環境
本記事のサンプルコードは、以下の環境で動作を確認しています。他の環境では動作しないか、動作が不安定になる可能性があります。
-
macOS Sequoia
- Node.js 26.3
Setはただの「重複のないコレクション」なのか
Setは、ArrayやMapと並ぶECMAScriptにおける代表的なコレクションの一つです。これらのコレクションはそれぞれ以下の表の性質を備えており、使い分けられています。
| コレクション | 概要 |
|---|---|
| Array | 順序のあるデータ構造。インデックスを指定して任意の位置のデータを取り出せる。データの重複が許容される。他言語におけるList(リスト)に相当する機能を備える |
| Map | 順序を持たず、キーと値のペアによってデータを保持するデータ構造。キーを指定することで、任意のデータを取り出せる。キーの重複はできない |
| Set | 順序を持たないデータ構造。インデックスを指定してデータを取り出すことはできない。データの重複が許容されない |
ArrayとMapは、極めて多くの局面で利用されます。Arrayは、データベースから取得したデータの格納などに用いられますし、Mapはフォームのname属性とvalue属性の対応表などに用いられます。いずれもその特性を生かし、適した用途に使われています。
SetはArrayに似ているようで異なる
ここでSetです。Setは、いわば「重複なしコレクション」です。Arrayのようにデータを追加していくことができますが、以下の点が決定的に異なります。
- データの重複が許容されない(重複になる追加は無視される)
- データ位置(インデックス)を指定してのデータ取得はできない(順序を持たない)
こういった挙動を、以下の具体的なコードで確かめてみます。
const set = new Set();
set.add(1); // addメソッドで追加
set.add(2);
set.add("Hello");
set.add(2); // 重複したaddは無視される
// console.log(set.get(1)); // エラー
for (const value of set) { // 拡張for文でのデータ取得は可能
console.log(value);
}
// 1
// 2
// Hello
// hasメソッドでデータの有無を確認できる
console.log(set.has(1)); // true
console.log(set.has(3)); // false
set.delete(2); // 削除はdeleteメソッド
console.log(set.has(2)); // false
set.clear(); // 全要素の消去
console.log(set.size); // 0(sizeプロパティで要素数を取得)
Setの基本的な操作は、addメソッドによるデータの追加、hasメソッドによる存在確認、deleteメソッドやclearメソッドによるデータの削除です。データの個数はsizeプロパティで取得でき、拡張for文で全要素を取得できますが、getメソッドとは異なり、インデックスを指定したデータの取得はできません。
Setの使いどころは基本的には「集合」
ここまでSetの基本を見てきました。Setは、データの順序はないのでインデックスによる個別の取り出しはできず、存在するかしないかの判定ぐらいしかできないので、ArrayやMapに比べると使いどころがイメージしにくいようです。
そのため、「コレクションとしてはとりあえずArrayとMapをやっておけばいいよね?」と不遇に扱われることもあるようです。実際のところどうなのでしょうか?
あえて言うまでもないのですが、Setとは「集合」を意味します。集合とは数学におけるデータの集まりを意味するもので、それをデータ構造として表現したものがSetと言えます。つまり、Setは数学の集合のように扱うのが妥当と言えます。
では、集合の用途とはどのようなものが考えられるでしょうか。たとえば、以下の用途が挙げられるでしょう。
- アンケート分析:複数回答の重なりを見る
- 顧客分析:購入履歴や属性の共通部分を調べる
- 検索システム:「AND」「OR」「NOT」検索を実現する
- データベース:SQLの結合・抽出・除外に対応する
- プログラミング:リストから重複除去・差分抽出を行う
- 権限管理:ユーザーが持つ権限の重なりや不足を調べる
- 確率:事象の和・積・余事象を扱う
- 論理回路/条件分岐:AND、OR、NOTに対応する
- スケジュール調整:参加可能日や空き時間の共通部分を探す
- 重複チェック:複数リスト間で同じ要素を見つける
このように、集合は「条件に合うものを整理・抽出・比較する」場面で使うのが適しているようです。しかしながら、こういった処理には集合に対する演算、すなわち数学における「集合論的な」演算が必要です。
集合を結合する「和」、差分を取り出す「差」などの演算が不可欠ですが、従来のSetではこのような演算は使えませんでした。
そこで配列を中間媒体に使って、
- SetをArrayに変換
- filterをはじめとするArrayのメソッドで抽出処理
- Arrayを再びSetに変換
といったコードを書いて該当する演算を実現していたわけです。
「具体的にどういったコードであったか?」は個別のメソッドで紹介していきますが、変換処理が入ることで性能面によくなさそうですし、可読性にも問題がありそうです。
そこで、Setオブジェクトのままで演算処理を行いたいというモチベーションが当然のごとく生まれます。これを受けて登場したのが、New Set methodsです。
