基礎から学ぶReact/React Hooks学習メモ 1 JavaScript基礎

# JavaScript基礎

## 変数と宣言

- グローバルスコープ・・・どこからでもアクセスできる
- ローカルスコープ・・・関数内からアクセスできる
    - 関数スコープ
    - ブロックスコープ

```js
const global = 'global';

const sampleFunc () => {
  const local = 'local';
}
```

- const 再代入不可
- let 再代入可能（初期化しないとundefinedで初期化される）

## 命名規則

- upperキャメルケース
    - コンポーネント名
    - クラス名
- lowerキャメルケース
    - 変数名
    - メソッド名
    - プロパティ名
^ スネークケース
    - 定数名

## データ型

- undefined
    - 型が未定義
- null
    - 型は決まっているが値が存在しない
- boolean
    - true/false
- string
    - 文字列
- number
    - 整数、浮動小数点数
- object
    - 配列、正規表現、Dateなど
- function
    - 関数
- symbol
    - 不変な値
- bigint
    - 巨大な数

### テンプレートリテラル

- 文字列の中で変数を展開する

```js
const hello = `Hello, ${name}`;
```

## 演算子

- `+ - * /` 四則演算
- `%` あまり
- `**` べき乗
- `+`は文字列の結合の機能もある（どちらかが文字列の場合、文字列結合する）
- `++ --` インクリメント／デクリメント
- `=== !===` 厳密等価／不等価演算子（型の一致もみる。基本的にはこちらを使う）
- `== !=` 等価／不等価演算子
- `> >= < <=` 大なり、以上、小なり、以下
- `&& || !` AND、OR、NOT
- `ex1 ? ex2 : ex3` 三項演算子

### Nullish coalescing Operator

- ex1がnull or undefinedのとき、ex2を返す。それ以外はex1を返す。

```js
ex1 ?? ex2
```

## 関数と宣言

- function

```js
function sampleFunc(a, b) {
  return a * b;
}
sampleFunc(1, 2);
```

- 無名関数

```js
const sampleFunc = function(a, b) {
  return a * b;
}
sampleFunc(1, 2);
```

- アロー関数

```js
const sampleFunc1 = (a, b) => {
  return a * b;
}
const sampleFunc2 = (a, b) => a * b;
const sampleFunc3 = a => a * 2;
const sampleFunc4 = () => 2;
```

# 引数

- 引数が多い場合は無視される

```js
const sampleFunc2 = (a, b) => a * b;
// 3は無視される
sampleFunc2(1 , 2, 3)
```

- コールバック関数

```js
setTimeout(() => {
   console.log('3秒後に呼ばれる');
}, 3000);

// ↑を分けて書く
const callBack = () => console.log('3秒後に呼ばれる');
setTimeout(callBack, 3000);
```

- デフォルト引数

```js
const sampleFunc = function(a = 1, b = 2) {
  return a * b;
}
// 引数がない場合、デフォルト値が使われる(1, 2)
sampleFunc()
```

- 可変長引数

```js
const sampleFunc = function(a, b. ...rest) {
  console.log(rest);
}
// a=1, b=2, rest=[3, 4, 5, 6, 7]
sampleFunc(1, 2, 3, 4, 5, 6, 7)
```

- 引数の分割代入

```js
const user = {
  name: 'Taro',
  message: 'Hello!'
}
const sampleFunc({ message }) => console.log(message);

// Hello!
sampleFunc(user);
```

## 条件分岐とループ

- `if`
- `switch`
- `for`
- `for...in`
    - key（ない場合はindex）をループ
    - 順番不定
- `for...of`
    - 値をループ
    - 順番通り
- `while`
    - trueが続く限りループ
- `do...while`
    - trueが続く限りループ
    - 最低1回は回る

## 配列

- 配列の基本
    - 空の文字列 
    - 文字列を宣言
- 配列へのアクセス `配列[index]`

```js
const emptyArr = [];
const stringArr = ["文字列01", "文字列02", "文字列03"];

console.log(stringArr[0]);  // 文字列01
console.log(stringArr[10]); // undefined
```   

- 配列であるかの判定 
    - `Array.isArray(obj)`
- 配列から要素を検索する
    - `配列.indexOf(検索値)` インデックスを返す。なければ-1
    - `配列.includes(検索値)`　true/falseを返す
- 配列の個数
    - `配列.length()`
- 配列から文字列への変換
    - `配列.toString()` カンマ区切りで出力される
- 配列の連結
    - `配列1.concat(配列2, 配列3)` 
    - ` [...配列1, ...配列2, ...配列3]` スプレッド構文を使用
    - `配列.join("/")` 配列の要素を指定したセパレータで結合
- 配列のソート
    - `配列.sort()` 破壊的
    - `配列.reverse()` 破壊的
    - `配列.sort((a,b) => a - b)` 比較関数を使用する。破壊的
    - `配列.concat().sort()` or `[...配列].sort()` 破壊的ではない
- 配列の削除
    - `配列.pop()` 最後の要素を取り出して、削除
    - `配列.shift()` 最初の要素を取り出して、削除
    - `配列.splice(index, 削除する要素数)` index番目～削除する要素数を取り出して、削除
    - `配列.splice(index, 削除する要素数, 追加する要素)` index番目～「削除する要素数」を取り出して、削除。先頭に「追加する要素」を追加
- 配列の追加
    - `配列.push(要素)` 最後に追加 
    - `配列.unshift(要素)` 最初に追加 
- 配列のフラット化

```js
const sampleArr = [[1, [2, [3, 4]], 5], [6]];
sampleArr.flat() // [1, [2, [3, 4]], 5, 6];
sampleArr.flat(2) // [1, 2, [3, 4], 5, 6];
sampleArr.flat(Infinity) // [1, 2, 3, 4, 5, 6];
```

- 分割代入

```js
const sampleArr = ["東京", "神奈川", "埼玉", "千葉", "茨城"];
const [tokyo, kanagawa, saitama, ...prefectures] = sampleArr;
console.log(prefectures); //  ["千葉", "茨城"]
console.log(...prefectures); //  千葉 茨城
```

- 配列の高階関数
    - `配列.forEach(value, [index], [array])`
        - 反復処理
    - `配列.map(value, [index], [array])`
        - 変換処理。非破壊的
    - `配列.filter(value, [index], [array])`
        - 抽出処理。非破壊的
    - `配列.find(value, [index], [array])`
        - 最初に一致した値を返す。見つからない場合undefined
    - `配列.findIndex(value, [index], [array])`
        - 最初に一致したindexを返す。見つからない場合-1
    - `配列.every(value, [index], [array])`
        - すべての条件が一致するときにtrueを返す。それ以外false
    - `配列.some(value, [index], [array])`
        - いずれかの条件が一致するときにtrueを返す。それ以外false
    - `配列.reduce((accumulator, currentValue, [currentIndex], [array]) => { 処理 }, initialValue)`
        - 最後のaccumulatorを返す
        - accumulatorは、前回returnの値
   
## オブジェクト

- オブジェクトとプロパティ
    - `key: value`

```js
const sampleObj ~ {
  key1: "value1",
  key2: "value2",
  key3: "value3"
}
```

- プロパティへのアクセス
    - ドット記法
    - ブラケット記法

```JS
// ドット記法
console.log(user.name);
// ブラケット記法
console.log(user["name"]);
```

- プロパティの変更、追加、削除

```JS
// 変更
point.y = 200
// 追加
point.z = 300
// 削除
delete point.z
```

- スプレッド構文とレスト構文

```JS
// points01オブジェクトとpoints02オブジェクトをマージ
const points = {...points01, ...points02}

// レスト構文 a,bを除いたプロパティがrestに代入される
const {a, b, ...rest} = points03
```

- key、value、プロパティの取り出し
    - `Object.keys(obj)`
        - keyの配列を出力
    - `Object.values(obj)`
        - valueの配列を出力
    - `Object.entries(obj)`
        - `[[key1, value1], [key2, value2], ... ]` のような配列を出力

- オブジェクトを要素に持つ配列

```js
const posts = [
  {
    id: 1,
    content: "今日は楽しい",
    likes: 2,
  }.
  {
    id: 2,
    content: "プログラミングしたい",
    likes: 3,
  },
  {
    id: 3,
    content: "勉強する",
    likes: 1,
  }
]

posts.forEach((post) => {
  return console.log(`${post.id} ${post.contents} ${post.likes}いいね！`)
})
```
 
## モジュール

- 名前付きexport、import

```js
// 名前付きexport
const sampleVariable = "sample!";
const sampleFunc = () => console.log("Hello, React!");
export {sampleVariable, sampleFunc}

// または
export const sampleVariable = "sample!";
export const sampleFunc = () => console.log("Hello, React!");
```

```js
// 名前付きimport
import {sampleVariable, sampleFunc} from "./namedExportModule.js"

console.log(sampleVariable)
console.log(sampleFunc())

// エイリアスを使った名前付きimport
import {
  sampleVariable as myVariable,
  sampleFunc as myFunc
} from "./namedExportModule.js"
```

- デフォルトexport、import
    - モジュールごとに1つだけエクスポートできるので、インポートする側も何をインポートすれば良いか明確
    - デフォルトインポートの場合、`{}`は不要

```js
// デフォルトエクスポート
export default function App() {
  console.log("Hello, App!")
}
// 関数名は省略可
export default function() {
  console.log("Hello, App!")
}
```

```js
// デフォルトインポートは{}が不要。任意の名前を付ける
import App from "./defaultExportModule.js"
```

- 再エクスポート
    - 一度インポートしたモジュールを別ファイルが利用できるようにエクスポートし直す
    - `export ... from ...`

```js
export {sampleVariable, sampleFunc} from "./namedExportModule.js"
```

- HTMLファイルからモジュールを呼び出す
    - type属性に`module`を指定する

```html
<script type="module" src="./modules/importModule.js"></script>
```

## 非同期処理

- setTimeout(callback, delay)
    - delayミリ秒遅れて1度だけ処理。
- setInterval(callback, during)
    - duringミリ秒ごとに繰り返し処理。前回の処理が終了しなくても繰り返し処理が行われる。

```js
setTimeout(() => {
  console.log("実行されました!")
}, 500)
```

- Promise
    - Pending 実行中 or 初期。
    - Fulfilled 処理が成功して終了。`.then()`を呼び出す。
    - Rejected 処理が失敗。`.catch()`を呼び出す。


```js
// Promiseインスタンスを生成
const promise = new Promise((resolve, reject) => {
  // ...
  resolve("成功！") // promiseをFulfilled状態にして、引数をthenのコールバック関数に渡す
  // ...
  reject(new Error('error')); // promiseをRejected状態にして、引数をcatchにコールバック関数に渡す
})

promise.then((value) => {
  console.log(value)

  // then内でthrowした場合は、rejectを意味するため、catchが呼び出される
  throw new Error("例外！！")

}).catch((error) => {
  console.error(error.message)
}).finally(() => {
  console.log("成功しても失敗しても呼び出されるよ")
})
```

- Promise.all()
    - Promiseオブジェクトすべての非同期処理が成功した場合の結果を受け取る
- Promise.race()
    - 非同期処理を並列に実行し、最初に応答があった時点での成功／失敗を1度だけ受け取る

```js
const promiseObjects = [promiseObj01, promiseObj02, promiseObj03]
Promise.all(promiseObjects)
.then(() => {
  console.log("すべての非同期処理が成功！")
}).catch(() => {
  console.log("非同期処理はすべて成功しませんでした！")
})


Promise.race(promiseObjects)
.then(() => {
  console.log("最初に終わった非同期処理が成功！")
}).catch(() => {
  console.log("最初に終わった非同期処理は成功しませんでした！")
})
```

- Async Function(async/await)
    - 関数の前に `async` を付けるだけで非同期関数を定義できる
    - Promiseインスタンスを返す関数を定義する構文で、`await`は`async Function`の中でのみ利用可能で、Promiseの状態(resolve/reject)が返されるまで処理を停止して待機する。
- asyncの使用例

```js
const sampleFunc01 = async () => {
  // ...
  return "非同期関数" // thenを呼び出す
  // ...
  throw new Error("エラー") // catchを呼び出す
}

// thenでつなぐことができる
sampleFunc01().then((value) => console.log(value)).catch((error) => console.error(error.message))
```

- awaitの使用例

```js
const sampleResolve = (value) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(value);
        }, 1000);
    })
}

const sampleAwait = async () => {
    const a = await sampleResolve(10);
    const b = await sampleResolve(20);
    const c = await sampleResolve(30);
    return a + b + c;
}

sampleAwait().then((v) => {
    console.log(v);  // 60
});
```


参考
- [基礎から学ぶReact/React Hooks](https://www.amazon.co.jp/dp/B09CP8T4TX)