This article is in need of a technical review.
This article is in need of an editorial review.
本章では、キーによって順序付けされたデータのコレクションを紹介します。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は(===に反して)自身と等しいと見なされます。