この記事は技術レビューを必要としています。ぜひご協力ください。
この記事は編集レビューを必要としています。ぜひご協力ください。
本章では、キーによって順序付けされたデータのコレクションを紹介します。Map オブジェクトと Set オブジェクトは挿入順に反復処理を行える要素を内蔵しています。
Map
Map
オブジェクト
ECMAScript 6 で値と値とをマッピングする新しいデータ構造が導入されました。Map
オブジェクトはシンプルなキー / バリューマップで、挿入順に要素を反復処理することができます。
次のコードでは Map
を用いたいくつかの基本的な操作を表しています。また、追加の例や詳細な API については、Map
リファレンスページをご覧ください。for...of
ループを使って、各反復処理において [key, value]
からなる配列を返しています。
var sayings = new Map(); sayings.set("dog", "woof"); sayings.set("cat", "meow"); sayings.set("elephant", "toot"); sayings.size; // 3 sayings.get("fox"); // undefined sayings.has("bird"); // false sayings.delete("dog"); for (var [key, value] of sayings) { console.log(key + " goes " + value); } // "cat goes meow" // "elephant goes toot"
Object
と Map
との比較
伝統的に、オブジェクト は文字列に値をマップするために使われてきました。オブジェクトを使うことで、キーを値に設定し、これらの値を取得し、キーを削除し、キーに値が格納されているかどうかを検出することができます。しかし、より便利な Map
オブジェクトを使うことでさらなる利点が得られます。
Object
のキーはString
オブジェクトですが、Map
なら任意の値を使えます。Object
はサイズを手作業で監視する必要があるのに対し、Map
は簡単にサイズを取得できます。Map
の反復処理は要素の挿入順に行われます。Object
はプロトタイプを持っているので、オブジェクトによるマップにはデフォルトキーが存在します(これはmap = Object.create(null)
を使って回避できます)。
Map
と Object
のどちらを使用すべきかを決めるには下記の 2 つのヒントが役立つでしょう :
- 実行時までキーが不明なとき、またはすべてのキーが同じ型、すべての値が同じ型のときはオブジェクトよりもマップを使用しましょう。
- 個々の要素に操作できるロジックがある場合はオブジェクトを使用しましょう。
WeakMap
オブジェクト
WeakMap
オブジェクトは、キーはオブジェクトのみで、対応する値は任意の値にできるキー / バリューのペアからなるコレクションです。キーによるオブジェクト参照は弱く保持されます、つまり、オブジェクトへの参照が存在しないときはガベージコレクション (GC) の対象になります。WeakMap
API は Map
API と同じです。
Map
オブジェクトとの違いは、WeakMap
のキーは列挙可能ではないことです(すなわち、キーのリストを取得するメソッドがありません)。もしも列挙可能であれば、リストはガベージコレクションの状態に依存し、非決定的になってしまいます。
詳細やサンプルコードについては、WeakMap
リファレンスページの「なぜ WeakMap なのか?」もご覧ください。
WeakMap
オブジェクトのよくある使用方法のひとつとして、オブジェクトに対するプライベートデータの格納、あるいは詳細な実装の遮蔽があります。次の例は Nick Fitzgerald 氏のブログ投稿、"Hiding Implementation Details with ECMAScript 6 WeakMaps"(ECMAScript 6 WeakMaps を使って実装の詳細を遮蔽する)によるものです。プライベートデータとプライベートメソッドはオブジェクトの内部に属していて、WeakMap オブジェクト、privates
内に格納されています。インスタンス上で公開されているものすべてとプロトタイプはパブリックになっています。すなわち、privates
はモジュールから公開されていないので、他のすべてのものは外部からはアクセスできません。
const privates = new WeakMap(); function Public() { const me = { // ここにプライベートデータが置かれる }; privates.set(this, me); } Public.prototype.method = function () { const me = privates.get(this); // `me` 内のプライベートデータに対し処理を行う…… }; module.exports = Public;
Set
Set
オブジェクト
Set
オブジェクトは値によって構成されるコレクションです。挿入順に要素を反復処理することができます。Set
内にある値は 1 回だけのみ生成されます。つまり、Set
のコレクション内では値は一意となります。
以下のコードでは Set
を用いた基本的な操作を表しています。さらなる例や API の詳細については、リファレンスの Set
ページもご覧ください。
var mySet = new Set(); mySet.add(1); mySet.add("some text"); mySet.add("foo"); mySet.has(1); // true mySet.delete("foo"); mySet.size; // 2 for (let item of mySet) console.log(item); // 1 // "some text"
Array
と Set
間の変換
Array.from
または展開演算子を使用して、Set
から Array
を生成できます。また、Set
コンストラクタを使って Array
から Set
へと逆変換することができます。Set
オブジェクトは一意の値を格納することにくれぐれも注意してください、Array
から重複した要素は変換するときに削除されます。
Array.from(mySet); [...mySet2]; mySet2 = new Set([1,2,3,4]);
Array
と Set
との比較
伝統的に、多くの状況において要素集合は JavaScript の配列に格納されてきました。しかし、新しい Set
オブジェクトには少なからず利点があります :
- 配列の
indexOf
を使用してコレクション内要素の有無を調べる方法は低速です。 Set
オブジェクトは値を使って要素を削除できます。配列では要素のインデックスに基づいて取り除く必要があります。indexOf
で配列内のNaN
値を検索することはできません。Set
オブジェクトは一意の値を格納します。自ら重複を監視する必要がありません。
WeakSet
オブジェクト
WeakSet
オブジェクトは、オブジェクトのコレクションです。WeakSet
内のオブジェクトは一度しか生成されません。つまり、WeakSet
コレクション内では値は一意となり、オブジェクトは列挙可能ではありません。
Set
オブジェクトとの主な違いは下記の通りです :
Set
とは対照的に、WeakSet
はオブジェクトのみのコレクションで、任意の型からなる任意の値のコレクションではありません。WeakSet
は弱いバージョンのSet
です。コレクション内のオブジェクトへの参照は弱く保持されています。WeakSet
内に格納されているオブジェクトに対する参照がなくなった場合、ガベージコレクションの対象になります。これはまた、現在コレクション内に格納されているオブジェクトのリストがないということです。WeakSet
は列挙可能ではありません。
WeakSet
オブジェクトの使用例は限定的です。メモリリークが発生しないため、例えば、DOM 要素をキーとして使用し、監視目的でそれらを記録することが安全に行なえます。
Map
と Set
におけるキーとバリューの等値性
Map
オブジェクトのキーの等値性と Set
オブジェクトの値の等値性は、両方とも 「same-value-zero アルゴリズム」に基づいています :
- 等値性は同値比較演算子
===
のように機能します。 -0
と+0
は等しいと見なされます。NaN
は(===
に反して)自身と等しいと見なされます。