【JavaScript】分割代入いろいろ

# 分割代入
:::note info
分割代入とは...
**オブジェクト / 配列 から プロパティ を取り出して個別の変数に代入すること**
::: 
## 1. オブジェクトの分割代入
通常、オブジェクトからプロパティを取り出す場合、<font color="red">**プロパティアクセサー**</font> を用いる。

:::note info
<font color="red">**プロパティアクセサー**</font>
オブジェクトのプロパティへのアクセスを提供するもので、「ドット記法」「ブラケット記法」がある
:::

```js
const item = { price: 100 };
const price = item.price; // プロパティアクセサー（ドット記法）
```
プロパティアクセサーを使ったコードと同等の処理を分割代入にすると
```js
const item = { price: 100 };
const { price } = item; // 分割代入
```
:::note info
**分割代入**
- 中カッコ `{ }` に取り出したいプロパティを指定することで、**プロパティ名と同じ名前の変数名** が作れる
- 同じプロパティ名を2度書かなくてよい

**<font color="red">const { プロパティ名と同じ変数名 } = オブジェクト</font>**
:::

### :small_red_triangle_down: 複数のプロパティを取り出す
```js
const person = {
  name: 'Taro',
  age: 20,
};
```
分割代入を使って person オブジェクトから name と age を取り出す。

```js
const { name, age } = person; // const { プロパティ名と同じ変数名 } = オブジェクト
```
中カッコ `{ }` で変数名を囲んで、オブジェクトのプロパティ名と同じ名前の変数を作成することができる。

```js
console.log(name); // 'Taro' ・・・ const name = person.name
console.log(age); // 20 ・・・ const age = person.age
```
分割代入は、取り出すプロパティ数が多い場合に効果を発揮する。

```js
const color = { r: 255, g: 255, b: 255, a: 1 };

const r = color.r;
const g = color.g;
const b = color.b;
const a = color.a;
```
分割代入を用いると、
```js
const { r, g, b, a } = color;
```

### :small_red_triangle_down: オブジェクトの分割代入で変数名を変える
```js:例）フロパティ名と変数名が同じ場合
object = { 
 hoge: hoge,
 fuga: fuga,
}
```
プロパティ名と変数名とが同じ場合、<font color="red">**短縮記法（省略記法）**</font>で書き直せる。
```js:短縮記法（省略記法）
object = { 
 hoge,
 fuga
}
```

:::note info
<font color="red">**短縮記法（省略記法）**</font>
「プロパティ名: 変数名」 変数名がプロパティ名と同じ場合に省略できる。
:::

```js
const { hoge } = object;
```
```js
const { hoge: hoge } = object; //　{ }の中は、プロパティ名: 変数名
```

**変数名はプロパティ名と同じである必要はなく、変数名を書き換えることもできる。**

```js
const color = { r: 255, g: 255, b: 255, a: 1 };

const { r: red, g: green, b: blue, a: alpha } = color;
// const { r, g, b, a } = color;
console.log(green); // 255 
// つまり、const green = color.g になっている
```
### :small_red_triangle_down:  入れ子構造の分割代入（オブジェクト）
```js:例
const country = {
  name: "日本",
  capital: {
    city: "東京",
    area: "23区",
  },
  language: "日本語",
};
```
分割代入を使って country オブジェクトから city と area を取り出す。

```js
const { 
  capital: { city, area },
} = country;

console.log(city); // "東京"　つまり、const city = country.capital.city;
console.log(area); // "23区"　つまり、const area = country.capital.area;
```
### :small_red_triangle_down: デフォルト値を設定する

オブジェクトの分割代入では、**<font color="red">指定したプロパティがオブジェクトに存在しない場合、その変数の値は undefined になる。**</font>

```js
const obj = { foo: 20 };

const { foo, bar } = obj; //分割代入

console.log(foo); // 20  (obj に foo がある)
console.log(bar); // undefined  (obj に bar がない)
```
**<font color="red">undefinedを未然に防ぎたい場合、**</font>
bar = 100 として **<font color="red">デフォルト値に設定すると、デフォルト値が使われる。**</font>
```js:例）存在しない要素がある（オブジェクト）
const obj = { foo: 20 };
const { foo, bar = 100 } = obj;

console.log(foo); // 20
console.log(bar); // 100  (undefined だった bar にデフォルト値が使われる)
```
### :small_red_triangle_down: Rest構文 (...rest) で残りのプロパティを取得する
`rest構文 (...rest) `は、残りの要素をまとめるために使用する。
```js
const profile = {
  name: "Yamada",
  height: 165,
  weight: 55
};

const { name, ...rest } = profile;

console.log(name);       // "Yamada"
console.log(rest.height); // 165
console.log(rest.weight);  // 55
```

## 2. 配列の分割代入
通常、配列から要素を取り出す場合、<font color="red">**インデックスアクセス**</font> を用いる。

:::note info
<font color="red">**インデックスアクセス**</font> 
インデックスを使って、配列の要素を参照する記法。
:::

```js
const numbers = [1, 2, 3, 4, 5];
// 配列から最初の3つの要素を取り出す
const first = numbers[0]; //インデックアクセス
const second = numbers[1]; //インデックアクセス
const third = numbers[2]; //インデックアクセス
```
:::note info
**配列の分割代入**
- **任意の変数名を使う** ・・・(オブジェクトの分割代入と違う)
- 配列の要素にインデックス (`[]`) を使わなくてよい

**<font color="red">const [ 任意の変数名 ] = 配列</font>**
:::
分割代入を使って取り出すと
```js
const numbers = [1, 2, 3, 4, 5];
const [first, second, third] = numbers; //変数名は任意
```
### :small_red_triangle_down: 不要な要素がある場合
不要な要素はカンマ（,）を使ってその位置を指定し、不要部分をスキップする。
```js
const numbers = [1, 2, 3, 4, 5];
const [, second, third] = numbers; //変数名は任意
console.log(second,third) // 2,3

// const [, second, third, , ] = numbers; 余分なカンマはエラーにはならないが不要
```

### :small_red_triangle_down: デフォルト値を設定する場合

配列でも同様に、存在しない要素がある場合、undefined になるため、undefined を未然に防ぐにはデフォルト値を使う。
```js:例）存在しない要素がある（配列）
const arr = [10, 20];
const [first, second, third = 30] = arr;

console.log(first);  // 10
console.log(second); // 20
console.log(third);  // 30 (存在せずundefinedだった要素に、デフォルト値を適用)
```
### :small_red_triangle_down: Rest構文 (...rest) を使う場合

```js:例）配列のRest構文 (...rest)
const arr = [1, 2, 3, 4, 5];
const [first, second, ...rest] = arr;

console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
console.log(rest[0]); // 3
```
:::note warn
<font color="red">**スプレッド構文 (...rest) は、要素の最後に使う**</font>
:x:  const [first, ...rest, last] = arr; 　// SyntaxError
:::

### :small_red_triangle_down: 入れ子構造の分割代入（配列）
```js:例）入れ子構造の分割代入
const twoByTwo = [
  [1, 2],
  [3, 4],
];
const [[one, two], [three]] = twoByTwo;

console.log(one); // 1
console.log(two); // 2
console.log(three); // 3
```
`配列 [3, 4]` から、`three` だけを取り出し、`4` は無視される。**（配列内の余分な要素は無視される）**。

## ３. 関数のパラメータと分割代入
```js:例）分割代入を使わない場合
const person = {
    first: 'Taro',
    last: 'Yamada',
    country: 'Japan'
};

const fullName = (person) => {
    return `${person.first} ${person.last}`; // "Taro Yamada"
};

console.log(fullName(person)); // "Taro Yamada"
```
これを、分割代入を使った場合、
```js:例）関数の中で分割代入
const fullName = (person) => {
    const {first, last} = person; //分割代入
// ↑ この分割代入部分は以下と同じ意味
// const first = person.first;
// const last = person.last:
    return `${first} ${last}`; // "Taro Yamada"
};
```
引数の `person` に、`const {first, last} = person;` を代入すると、
```js:例）関数の中で分割代入
const fullName = ({first, last}) => {
    return `${first} ${last}`; // "Taro Yamada"
};
```
```js:例）関数の中で分割代入
// アロー関数はreturn を省略できるので、結果的に1行に書き換えれる
const fullName = ({ first, last }) => `${first} ${last}`; // "Taro Yamada"
```

:::note info
<font color="red">**関数パラメータでの分割代入のスタイル**</font>
:one:　**引数でオブジェクトを受け取り、関数内部で分割代入を使う**

```js
// オブジェクト person
const fullName = (person) => {
    const { first, last } = person; // 分割代入
    return `${first} ${last}`;
};
```
:point_right: 関数の引数でオブジェクトを受け取り、その後に内部で分割代入を使ってプロパティを取り出す。

:two:　**引数内で分割代入を使う**
```js
// first と last は、オブジェクトのプロパティ
const fullName = ({ first, last }) => {
    return `${first} ${last}`;
};
```
:point_right: 関数の引数でオブジェクト全体を引数として受け取り、その中から必要なプロパティをその場で抽出する。
:::
### :small_red_triangle_down: 関数のパラメータと分割代入 【Reactのprops編】

Reactでは、親コンポーネントから子コンポーネントへ情報を渡す際に、**propsオブジェクト**を使う。つまり、オブジェクトの分割代入を利用してpropsは記述できる。
子コンポーネントは、そのpropsオブジェクトのプロパティにアクセスして、渡されたデータを表示や処理をする。
**props は 「properties」 の略で、コンポーネントに渡されるデータを表すオブジェクトの事**

```react:例）渡す側　親コンポーネント
const ComponentA = () => {
  const userName = "山田太郎";
  const email = "taro@mail.com";

  return (
    <div>
      <h1>Hello, props!</h1>
      <p>コンポーネント間で props をやり取りする</p>
      <ComponentB userName={userName} email={email} />
    </div>
  );
};
```
```react:例）受ける側　子コンポーネント
const ComponentB = (props) => {
  return (
    <div>
      <h2>{props.userName}</h2>
      <p>{props.email}</p>
    </div>
  );
};
```
**:black_medium_small_square:関数内で分割代入を使うパターン**
```react:例）受ける側 （関数内で分割代入を使うパターン）
const ComponentB = (props) => {
  const { userName, email } = props;
  // const userName = props.userName;
  // const email = props.email;
  return (
    <div>
      <h2>{userName}</h2>
      <p>{email}</p>
    </div>
  );
};
```
**:black_medium_small_square:引数内で分割代入を使うパターン**
```react:受ける側 （引数内で分割代入を使うパターン）
const ComponentB = ({userName, email}) => {
  return (
    <div>
      <h2>{userName}</h2>
      <p>{email}</p>
    </div>
  );
};
``` 
## 4. 配列を返すメソッドと分割代入
`map()`, `filter()`,`split()`, `match()` など配列を返す代表的なメソッドと分割代入。

:small_red_triangle_down: **map()**
```js:例）分割代入を使わない場合
const users = [
  { name: "Taro", age: 25 },
  { name: "Jiro", age: 30 },
  { name: "Saburo", age: 18 }
];

const greetings = users.map(user => {
  return `${user.name} is ${user.age} years old`;
});
console.log(greetings);
// ["Taro is 25 years old", "Jiro is 30 years old", "Saburo is 18 years old"]
```
分割代入の場合、user をそのまま受け取らず、{ name, age } で name と age だけを取り出し、直接参照する。
```js:例）map()で分割代入
const greetings = users.map(({ name, age }) => {
  return `${name} is ${age} years old`;
});
```
:small_red_triangle_down: **filter()**
```js:例）分割代入を使わない場合
const users = [
  { name: "Taro", age: 25 },
  { name: "Jiro", age: 30 },
  { name: "Saburo", age: 18 }
];

const adults = users.filter(user => user.age >= 20);
console.log(adults);
// [ { name: "Taro", age: 25 }, { name: "Jiro", age: 30 } ]
```
分割代入の場合、user をそのまま受け取らず、{ age } で age だけを取り出し、直接参照する。

```js:例）filter()で分割代入を使う場合
const adults = users.filter(({ age }) => age >= 20);

// 以下と等価
// const adults = users.filter(user => {
//   const { age } = user; // user から age を取り出す
//   return age >= 20;
// });
```
:small_red_triangle_down: **split()**
```js:例）分割代入を使わない場合
const str = "apple banana orange";
const fruits = str.split(' '); // 配列を変数に格納

const first = fruits[0];
const second = fruits[1];
const third = fruits[2];

console.log(first);  // "apple"
console.log(second); // "banana"
console.log(third);  // "orange"
```
split(' ') により、["apple", "banana", "orange"] の配列が生成されるので、分割代入の場合、[first, second, third] のそれぞれの変数（任意）に値を直接代入。

```js:例）split()で分割代入
const [first, second, third] = str.split(' ');
// const [first, second, third] = ["apple", "banana", "orange"];
```
:small_red_triangle_down: **match()**

:::note warn
match() メソッドは null を返す場合 もあるため、null チェック を入れておく。
:::


```js:例）分割代入を使わない場合
const str = "Hello 123";
const match = str.match(/(\w+) (\d+)/);

const [fullMatch, word, number] = match;

if (match) {
  const fullMatch = match[0]; // 正規表現全体にマッチ
  const word = match[1];      // 1つ目のキャプチャグループ (\w+)
  const number = match[2];    // 2つ目のキャプチャグループ (\d+)

  console.log(fullMatch); // "Hello 123"
  console.log(word);      // "Hello"
  console.log(number);    // "123"
} else {
  console.log('No match found');
}
```
match の結果を直接分割代入して、必要な値を変数に割り当てる。
```
match = str.match(/(\w+) (\d+)/) の結果：
["Hello 123", "Hello", "123"]
```

```js:例）match()で分割代入
if (match) {
  const [fullMatch, word, number] = match; // 分割代入
  
  console.log(fullMatch); // "Hello 123"
  console.log(word);      // "Hello"
  console.log(number);    // "123"
} else {
  console.log('No match found');
}
```

## 5. ループ処理と分割代入
```js
for (let [key, value] of Object.entries(user)) { ... }
```
`Object.entries()メソッド`は、引数に与えたオブジェクトの各プロパティを [key, value] のペアの配列で返すメソッド。
```js:例）分割代入を使わない場合
const user = {
  name: "Yamada",
  age: 25,
  country: "Japan"
};

for (const entry of Object.entries(user)) {
  const key = entry[0];   // entry[0] で key を取り出す
  const value = entry[1];  // entry[1] で value を取り出す
  console.log(`${key}: ${value}`);
}
// name: Yamada
// age: 25
// country: Japan
```
Object.entries(user)の結果は以下。
```
[
  ['name', 'Yamada'],
  ['age', 25],
  ['country', 'Japan']
]
```
entry[0] や entry[1] を書かず、分割代入を使って key / value に直接代入すると
```
const key = entry[0];
const value = entry[1];
この部分を分割代入を使うと、const [key, value] = entry; と等価
```
```js:例）for...of ループで分割代入を使う場合
for (const [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`);
}
```

https://ja.javascript.info/destructuring-assignment

https://www.frontend-rpg.com/blog/7y2rh63s1r5

https://typescriptbook.jp/reference/values-types-variables/object/destructuring-assignment-from-objects

https://zenn.dev/yamap_web/articles/c197f56924b3fa

https://it-infomation.com/javascript-object-entries/