ES6以降の基本的なJavaScriptの書き方

## はじめに
本記事は改めてJavaScriptの記述についてまとめてみようと考え、
その中でも便利な機能や構文が追加されたES6(ES2015)以降の書き方を主にまとめていこうと思います。
バージョンによってはこの書き方では動かない環境もあるのでお気をつけください。

### 変数宣言
```js
// var: 再宣言可能、関数スコープ
var name = "Hoge";
var name = "HogeHoge"; // 再宣言可能
console.log(name); // HogeHoge

// let: 再宣言不可、ブロックスコープ
let name = "Hoge";
// let name = "HogeHoge"; // エラー: Identifier 'name' has already been declared
name = "HogeHoge"; // 再代入は可能
console.log(name); // HogeHoge

// const: 再宣言不可、再代入不可、ブロックスコープ
const name = "Hoge";
// const name = "HogeHoge"; // エラー: Identifier 'name' has already been declared
// name = "HogeHoge"; // エラー: Assignment to constant variable.
console.log(name); // Hoge
```

#### varの使用は避けた方が良い理由
関数スコープなので関数全体で有効になり、意図しない動作が発生することになります。
一度宣言するといろんなところで使えるのが便利だと思って使いがちですが、letとconstを使うようにしましょう。


### テンプレート文字列
```js
// 従来の方法: + を使った文字列連結
const name = "HogeHoge";
const age = 30;
const message = "私の名前は " + name + " で、年齢は " + age + " 歳です。";
console.log(message); // 私の名前は HogeHoge で、年齢は 30 歳です。

// テンプレート文字列
const name = "HogeHoge";
const age = 30;
const message = `私の名前は ${name} で、年齢は ${age} 歳です。`;
console.log(message); // 私の名前は HogeHoge で、年齢は 30 歳です。
```

### 分割代入
```js
const person = {
  name: "HogeHoge",
  age: 25,
  country: "Japan"
};

// オブジェクトのプロパティを個別の変数に分割して代入
const { name, age } = person;
console.log(name); // HogeHoge
console.log(age); // 25

// 配列の分割代入
const array = [1, 2, 3];

// 配列の要素を個別の変数に分割して代入
const [first, second] = array;
console.log(first); // 1
console.log(second); // 2
```

### スプレッド構文
```js
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]

const person = { name: "HogeHoge", age: 30 };
const updatedPerson = { ...person, age: 31 };
console.log(updatedPerson); // { name: "HogeHoge", age: 31 }
```

これは個人的によく使う場面に遭遇している気がします。
実際の処理としては、元のオブジェクトを残しつつ、新しいオブジェクトを作成してそのコピーを操作する流れになります。

```js
const person = { name: "HogeHoge", age: 30 };

// スプレッド構文を使って新しいオブジェクトを作成し、age プロパティを上書き
const updatedPerson = { ...person, age: 31 };

console.log(updatedPerson); // { name: "HogeHoge", age: 31 }
console.log(person); // { name: "HogeHoge", age: 30 } （元のオブジェクトは変更されていない）
```

ちょっと脱線しますがReactではコールバック関数（関数の引数として渡される関数）に
hooksのuseState関数を渡してその中でスプレッド構文する処理を使います。
```js
import React, { useState } from "react";

function App() {
  const [person, setPerson] = useState({ name: "HogeHoge", age: 30 });

  const addCountry = () => {
    // setPerson関数で状態を更新する
    setPerson(prevPerson => {
        // 現在のpersonオブジェクトをスプレッド構文でコピーし、新しいcountryプロパティを追加する
        return { ...prevPerson, country: 'Japan' };
    });
　　　};

  return (
    <div>
      <p>Name: {person.name}</p>
      <p>Age: {person.age}</p>
      <p>Country: {person.country}</p>
      <button onClick={addCountry}>Add Country</button>
    </div>
  );
}

export default App;
```

### アロー関数
```js
// 通常の関数
function add(a, b) {
  return a + b;
}

// アロー関数
const addArrow = (a, b) => a + b;

console.log(add(2, 3)); // 5
console.log(addArrow(2, 3)); // 5
```
関数の宣言はアロー関数を使いましょう。

### 配列操作メソッド
```js
const numbers = [1, 2, 3, 4, 5];

// map: 配列の各要素に関数を適用
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// filter: 条件を満たす要素のみを抽出
const even = numbers.filter(num => num % 2 === 0);
console.log(even); // [2, 4]

// reduce: 配列を一つの値に集約
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 15
```

### 三項演算子
```js
const age = 20;
const message = age >= 18 ? "成人です" : "未成年です";
console.log(message); // "成人です"
```

またまた余談ですがReactではmapと三項演算子の合わせ技を結構使う気がします。
```js
import React from "react";

function App() {
  const items = ["Apple", "Banana", "Cherry"]; // 試しに空配列 [] にすると違いがわかります

  return (
    <div>
      {items.length > 0 ? (
        items.map((item, index) => (
          <p key={index}>{item}</p>
        ))
      ) : (
        <p>アイテムがありません</p>
      )}
    </div>
  );
}

export default App;
```

### Promises
```js
// Promise　then の使用
// Promiseを使った関数
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("First data fetched"), 1000);
  });
};

// もう一つのPromise関数
const fetchMoreData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("Second data fetched"), 1000);
  });
};

// then を使った非同期処理の連鎖
fetchData()
  .then(data1 => {
    console.log(data1);
    return fetchMoreData(); // 次の非同期処理をチェーンに追加
  })
  .then(data2 => {
    console.log(data2);
  })
  .catch(error => {
    console.error(error);
  });
```
async/await(ES2017)
```js
const fetchAsyncData = async () => {
  try {
    const data1 = await fetchData();
    console.log(data1);

    const data2 = await fetchMoreData();
    console.log(data2);
  } catch (error) {
    console.error(error);
  }
};

fetchAsyncData();
```

## まとめ
PHPから始めた私にとってスプレッド構文やアロー関数、配列操作メソッドは
何をしてるか分かりませんでした。
慣れるととても便利なので積極的に使っていきたいです。