キー付きコレクション

本章では、キーによって順序付けされたデータのコレクションを紹介します。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");
sayings.has("dog"); //false

for (var [key, value] of sayings) {
  console.log(key + " goes " + value);
}
// "cat goes meow"
// "elephant goes toot"

sayings.clear();
sayings.size; // 0

ObjectMap との比較

伝統的に、objects は文字列を値にマップしてきました。オブジェクトを使うことで、キーを値に設定し、その値を取得し、キーを削除し、キーで何か格納されているかどうかを検出することができます、しかしながら、 Map より便利なことはごくわずかです。

  • Object のキーは Strings オブジェクトです、Map ならどんな値も使えるというのに。
  • Object はサイズを手作業で追跡する必要があるのに対し、Map は簡単にサイズを取得できます。
  • Map の反復処理は要素の挿入順に行われます。
  • Object はプロトタイプを持っているので、オブジェクトによるマップにはデフォルトキーが存在します(これは map = Object.create(null) を使って回避できます)。

MapObject のどちらを使用すべきかを決めるには下記の 3 つのヒントが役立つでしょう :

  • 実行時までキーが不明なとき、またはすべてのキーが同じ型、すべての値が同じ型のときはオブジェクトよりもマップを使用しましょう。
  • 数値、真偽値、どのプリミティブ値であるかどうかに関わらず、オブジェクトはそれぞれのキーを文字列として扱うためプリミティブ値をキーとして保存する必要がある場合にマップを使用しましょう。
  • 個々の要素に操作できるロジックがある場合はオブジェクトを使用しましょう。

WeakMap オブジェクト

WeakMap オブジェクトは、キーはオブジェクトのみ値は任意の値にできるキー / バリューのペアからなるコレクションです。キーによるオブジェクト参照は弱く保持され、オブジェクトへの参照が存在しないときはガベージコレクション (GC) の対象になります。WeakMap API は Map API と同じです。

Map オブジェクトとの違いの1つは、WeakMap のキーは列挙可能ではないことです(すなわち、キーのリストを取得するメソッドがありません)。もしも列挙可能であれば、リストは非決定性をもたらす、ガベージコレクションの状態に依存することになってしまいます。

詳細やサンプルコードについては、WeakMap リファレンスページの「なぜ WeakMap なのか?」もご覧ください。

WeakMap オブジェクトのよくある使用方法のひとつとして、オブジェクトに対するプライベートデータの格納、あるいは実装の細部の隠蔽があります。次の例は Nick Fitzgerald 氏のブログ投稿、"Hiding Implementation Details with ECMAScript 6 WeakMaps"(ECMAScript 6 WeakMaps を使って実装の詳細を隠蔽する)です。プライベートデータとメソッドはオブジェクトの内部に属していて、プライベートな WeakMap オブジェクトに格納されています。インスタンスから露出する全てとプロトタイプは公開されています、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つの値は 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"

ArraySet 間の変換

Array.from または展開演算子を使用して Set から Array を生成できます。また、Set コンストラクタを使って Array から Set へと逆変換することができます。Set オブジェクトは一意の値を格納することにくれぐれも注意してください、Array から重複した要素は変換するときに削除されます。

Array.from(mySet);
[...mySet2];

mySet2 = new Set([1,2,3,4]);

ArraySet との比較

伝統的に、要素の set は多くの状況において JavaScript の配列に格納されてきました。しかし、新しい Set オブジェクトにはいくつかの利点があります :

  • 配列の indexOf を使用してコレクションに要素が存在しているかどうかを調べるのは低速です。
  • Set オブジェクトは値を使って要素を削除できます。配列を結合する場合には要素のインデックを使って行います。
  • NaN 値は配列の indexOf で検索することはできません。
  • Set オブジェクトは一意の値を格納します、自ら重複を追跡する必要がありません。

WeakSet オブジェクト

WeakSet オブジェクトは、オブジェクトのコレクションです。WeakSet 内の1つのオブジェクトは1回だけ取り出せます; WeakSet コレクション内では値は一意で、オブジェクトは列挙可能ではありません。

Set オブジェクトとの主な違いは下記の通りです :

  • Set とは対照的に、WeakSetオブジェクトのみのコレクションで、任意の型の任意の値でのコレクションではありません。
  • WeakSet弱い : コレクションでのオブジェクトでの参照は弱く保持されています。WeakSet 内に格納されているオブジェクトに対する参照がなくなった場合、ガベージコレクションされます。これはまた、現在コレクション内に格納されているオブジェクトのリストがないということを表しています。WeakSet は列挙可能ではありません。

WeakSet オブジェクトの使用例は限定的です。メモリリークが発生しないため、例えば、DOM 要素をキーとして使用し、監視するためにそれらにマーキングすることが安全に行なえます。

MapSet におけるキーと値の等値性

Map オブジェクトのキーの等値性と Set オブジェクトの値の等値性は両方とも、 「same-value-zero アルゴリズム」に基づいています:

  • 等値性は同値演算子 === のように機能します。
  • -0+0 は等しいと見なします。
  • NaN は(=== とは逆に)自身と等しいと見なします。

ドキュメントのタグと貢献者

 このページの貢献者: kenji-yamasaki, chikoski, x2357, shide55
 最終更新者: kenji-yamasaki,