【JavaScript】Map/Set② 〜Set〜

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* Set、WeakSetオブジェクトについて
* Set、WeakSetオブジェクトで使用できるメソッドについて

# Set
* セット型のコレクションを扱うためのビルトインオブジェクト。
* 配列と異なり要素は順序を持たず、インデックスによるアクセスはできない。

> **セットとは**
> 重複する値がないことを保証したコレクションのこと。
> ※コレクションは「何らかのデータをまとめて格納するデータ構造」

# セットの作成と初期化
* Setオブジェクトをnewすることで、新しいセットを作成できる。
* コンストラクタの初期値として、`iterableオブジェクト`を渡すことができる。

```js
const set = new Set();
// 作成した時点では何も持っていない
console.log(set.size); // => 0
```
```js
// 配列はiterableオブジェクト
const numbers = [1, 2, 3, 3];

const set = new Set(numbers);
// セットは重複する値が存在しないことを保証するため同じ値は1つにまとめられる
console.log(set.size); // => 3
```

# 値の追加と取り出し
以下のようなセットの要素を扱うメソッドが存在する。

|メソッド|概要|構文|返り値|
|--|--|--|--|
|add|セットに新しい値を追加|mySet.add(value)|(要素が追加された)Setオブジェクト|
|has|セットが指定したvalueに紐づく要素を持っているか確認|mySet.has(value)|存在している場合「true」、存在しない場合「false」|
|delete|セットから指定した要素を削除|mySet.delete(value)|要素を削除できた場合「true」、指定した要素が存在しない場合「false」|
|clear|セットが持つすべての要素を削除|mySet.clear()|undefined|

```js
const mySet = new Set(["value1", "value2"]);
// 初期値のサイズ
console.log(mySet.size);              // => 2

// 新しい要素の追加
mySet.add("value3");
console.log(mySet.size);              // => 3

// 指定した値に紐づく要素を持っているか確認
console.log(mySet.has("value1"));     // => true
console.log(mySet.has("value4"));     // => false

// 指定した値に紐づく要素を削除
console.log(mySet.delete("value3"));  // => true
console.log(mySet.delete("value3"));  // => false

// セットが持つすべての要素を削除
console.log(mySet.clear());           // => undefined

console.log(mySet.size);              // => 0
```

# セットの反復処理
* セットが持つ値を反復処理するには、`forEachメソッド`を使用する。
* forEachメソッドではセットが持つすべての要素を、`セットへの挿入順`に反復処理が可能。
* また、Setオブジェクト自身も`iterableなオブジェクト`であるため`for...of文`で反復処理が可能。<br />(`keys`、`values`、`entries`メソッドが存在するが、Mapの`key`相当の物もないため、あまり有用的ではない)

```js
const mySet = new Set(["value1", "value2"]);

mySet.forEach((value, key, map) => {
  console.log(`value: ${value}`);
});
// => value: value1
// => value: value2

// Setオブジェクトをfor..ofで反復処理
for (const value of mySet) {
  console.log(value);
}
// => value1
// => value2
```

# WeakSet
* `Set`と同様に`セット`を扱うためのビルトインオブジェクト。
* WeakSetは`オブジェクトのみ`を扱うことができるコレクション。
* `Set`と同様に、 `WeakSet`内の各オブジェクトは重複しないことを保証。
* Setと違う点は、キーを[弱い参照（Weak Reference）](https://ja.wikipedia.org/wiki/%E5%BC%B1%E3%81%84%E5%8F%82%E7%85%A7)で持つこと。
* `WeakSet`内に格納されているオブジェクトへの参照が他にない場合、ガベージコレクションによりメモリ領域が解放される。

以下のようなセットの要素を扱うメソッドが存在する。(ここでのセットとはWeakSetのこと)

|メソッド|概要|構文|返り値|
|--|--|--|--|
|add|セットに新しい値を追加|myWeakSet.add(value)|(要素が追加された)Setオブジェクト|
|has|セットが指定したvalueに紐づく要素を持っているか確認|myWeakSet.has(value)|存在している場合「true」、存在しない場合「false」|
|delete|セットから指定した要素を削除|myWeakSet.delete(value)|要素を削除できた場合「true」、指定した要素が存在しない場合「false」|

```js
const obj1 = {};
const obj2 = {};
const obj3 = {};

const myWeakSet = new WeakSet([obj1, obj2]);

// 新しい要素の追加
myWeakSet.add(obj3);

// 指定した値に紐づく要素を持っているか確認
console.log(myWeakSet.has(obj3));     // => true
console.log(myWeakSet.has({}));       // => false

// 指定した値に紐づく要素を削除
console.log(myWeakSet.delete(obj3));  // => true
console.log(myWeakSet.delete(obj3));  // => false
```