【JavaScript】スプレッド構文の便利な使い方まとめ

## **スプレッド構文**

**```...```（ピリオド３つ）** と書きます。
配列ライクなオブジェクト（正確には **for of** で展開できるオブジェクト）を個々の値に展開することができます。

- [スプレッド構文 - MDN web docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_operator)

## **個々の値に展開する**
```JavaScript
const data = [15, -3, 78, 1];
console.log(Math.max(...data));    // 78

// もう以下のように書く必要はありません
console.log(Math.max.apply(null, data));
```

## **配列を複製する**

配列をコピー（新しく参照）する場合は **```Array.from()```**、**```[].slice.call()```** などを使いますがスプレッド構文を使うと以下のようにコーディングできます。

```JavaScript
const ary = ['Pen', 'Pineapple', 'apple'];
const myAry = [...ary];

console.log(ary === myAry);    // false
console.log(myAry);            // ["Pen","Pineapple","apple"]
```

要素の参照は保たれます。

```JavaScript
const fruits = [
  { 'banana': 100 },
  { 'cherry': 200 }
];
const myFruits = [...fruits];

fruits["0"].banana = 300;
console.log(myFruits);    // [{"banana":300},{"cherry":200}] ← myFruits[0].bananaも変わる
```

## **強力な配列操作**

以下のような配列があるとします。

```JavaScript
const data1 = [1, 2, 3];
const data2 = ['d', 'e', 'f'];
```

- より強力な**```.push()```**

```JavaScript
data1.push(...data2);
console.log(data1);    // [1,2,3,"d","e","f"]

// もう以下のように書く必要はありません
Array.prototype.push.apply(data1, data2);
[].push.apply(data1, datat2);
```

- より強力な **```.unshift()```**

```JavaScript
data1.unshift(...data2);
console.log(data1);    // ["d", "e", "f", 1, 2, 3]
```

- 配列をマージする

```JavaScript
const merged = ['あ', ...data1, 'い', ...data2, 'う'];
console.log(merged);    // ["あ",1,2,3,"い","d","e","f","う"]
```

## **配列を分割する**

```JavaScript
let [a, b, ...other] = [1, 2, 3, 4, 5];

console.log(a);        // 1
console.log(b);        // 2
console.log(other);    // [3, 4, 5]
```

分割代入と組み合わせると配列の分割も簡単です。

- [分割代入 - MDN web docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)

## **文字列を配列にする**

```JavaScript
const word = 'JavaScriptプログラミング';
const converted = [...word];

console.log(converted);    // ["J","a","v","a","S","c","r","i","p","t","プ","ロ","グ","ラ","ミ","ン","グ"]
```

もう空文字で分割する（ **```.split('')```**）する必要はありません。
**```Array.from(word)```** と書くよりシンプルです。

```JavaScript:example.js
const word = 'プログラミングJavaScript';

// 一文字づつ操作する。
[...word].forEach(c => console.log(c));    // ここでは一文字ずつ列挙してみました。

// - 文字列を反転する
const reversed = [...word].reduceRight((p, c) => p + c);    // 配列に変換し右から左へたたみ込む。
console.log(reversed);    // tpircSavaJグンミラグロプ
```


## **配列から重複を取り除く**


```JavaScript
const data = ['a', 'b', 'c', 'a', 'b', 'd'];
const dist = [...(new Set(data))];

console.log(dist);    // ["a","b","c","d"]
```

**Set** オブジェクトは重複しない値の集合を管理するためのオブジェクトです。
重複する値が追加された場合には、それを無視します。

## **可変長引数を定義する**

```JavaScript
const sum = (...nums) => nums.reduce((p, c) => p + c);

console.log(sum(1, 2, 3, 4, 5));     // 15
```

引数が可変長であることを明示できます。
**IDE**で表示され関数の利用者は引数が可変長であることがわかります。
![prrpIterable.png](https://qiita-image-store.s3.amazonaws.com/0/195024/6c75feea-921f-0c5a-369e-9ef73538de99.png)
**arguments** オブジェクトと違い、スプレッド構文で宣言された引数は **Array** です。
そのまま **.reduce()**、 **.filter()**、 **.map()** といった配列操作が行えます。

## **NodeList や HtmlCollection を配列のように操作する**

#### **NodeList や HtmlCollction に .filter() を掛ける**

```JavaScript
const elems = document.getElementByClassName('checkboxClassName');

// 取得した **NodeList** から、**checked** プロパティが **true** かつ **class** プロパティに **'foo'** が含まれているものを抽出します。
const filtered = [...elems].filter(el => el.checked && el.classList.contains('foo'));
```

#### **チェックボックスをチェック、リストボックスをセレクトする**

```JavaScript
const setCheckBox = (name, ...values) => {
  const elems = document.getElementsByName(name);
  elems.forEach(el => el.checked = values.includes(el.value));
}

setCheckBox('fruits', 'apple', 'banana');    // value が 'apple' 、'banana' のチェックボックスをチェックします。
```

ここまで読んでいただきありがとうございました。