JavaScriptの基礎

# 変数宣言

JavaScriptの変数宣言には3種類(var, const, let)の3つがあります。

 - [ ] const：再代入できない変数→定数扱い
 - [ ] let：再代入可能な変数
以下のように、ブロックススコープ外で宣言したhogeはブロックススコープ内でも宣言可能ですが、値はブロック数スコープ内でのみ有効
```javascript
let hoge = 100 // 変数hogeに100を代入

{
let hoge = 200 // 変数hogeに200を再代入
console.log(hoge) // ブロック内は200表示
}

console.log(hoge) // ブロック外では100表示
```
また、letで宣言した変数に初期値を代入しない場合、デフォルト値｢undefined｣で初期化される

- [ ] var
基本的にvarは使用しません。
変数宣言にはconstを使用し、変数の再代入が必要な場合のみ、letを使用する

# グローバル変数、ローカル変数

 - [ ] グローバル変数：プログラムどこからでもアクセス可能
 - [ ] ローカル変数：宣言されている関数内からのみアクセス可能

ローカル変数は更に**関数スコープ**と**ブロックスコープ**に分けられる

 - [ ] 関数スコープ：関数(function)毎に作られるスコープ
 関数スコープ内でconst, let, varのいずれかで宣言された変数、または関数の引数は宣言された関数内でのみ使用可能なローカル変数になる

- [ ] ブロックスコープ：ES2015から追加されたローカルスコープの概念
ブロックススコープ内でconst、またはletで宣言された変数は、ブロック内で使用できるローカル変数となる
ただし、ブロックススコープ内であっても、varで宣言された変数は、ブロック外で使用してもそのまま使用できてしまうので注意が必要

# 命名規則
命名規則の記法について以下のような種類があります。
 - [ ] アッパーキャメルケース：先頭と言葉の区切りは大文字、それ以外は小文字
 - [ ] ローワーキャメルケース：先頭は小文字で言葉の区切りは大文字、それ以外は小文字
 - [ ] スネークケース：全て大文字で、単語とにアンダースコア(_)で繋ぐ

上記の記法を用いて各要素を以下のように設定する
| 要素 | 記法名 | 例 |
|:-:|:-:|:-:|
|  コンポーネント名 | アッパーキャメルケース  | HogeFoo  |
| 変数名  | ローワーキャメルケース  | hogeFoo  |
| 定数名  | スネークケース  | HOGE_FOO  |
| メソッド名  | ローワーキャメルケース  | hogeFoo  |
| プロパティー名  | ローワーキャメルケース  | hogeFoo  |
| クラス名  | アッパーキャメルケース  | HogeFoo  |

# nullとnudefinedの違い

 - [ ] null：データ型が決まっているが値がない、または中身が空
 - [ ] undefined：データ型も値も決まっていない、または存在しない

## 比較演算子

 - [ ] hoge === foo：厳密等価演算子
 同じ型、かつ同じ数値であるか比較する 
 - [ ] hoge == foo：等価演算子
 同じ値であるか比較する(暗黙の型変換が行われている)

```javascript
null === undefined // false
null == undefined // true

// hogeがnull、またはundefinedの場合、fooを返す
// hogeがnull、またはundefinedで内場合、hogeを返す
hoge ?? foo
```

# 関数と宣言
関数を宣言する方法は大きく分けて3つ存在する
 - [ ] functionを利用した関数宣言
 - [ ] 無名関数による定義
 - [ ] アロー関数による定義

## 通常の関数宣言
```javascript
function sampleFunc(hoge, foo) {
    const sampleValue = hoge + foo;
    return sampleValue;
}

sampleFunc(2, 3) // 5
```

## 無名関数
```javascript
// 関数を変数に代入する
// 変数名(sampleFunc)はあるが、関数名はない
const sampleFunc = function(hoge, foo) {
    const sampleValue = hoge + foo;
    return sampleValue;
}

sampleFunc(2, 3) // 5 
```

## アロー関数
```javascript
// より短く関数を記述できる
const sampleFunc = (hoge, foo) => {
    const sampleValue = hoge + foo;
    return sampleValue;
}

sampleFunc(2, 3) // 5

// 引数が1つの場合は、()を省略できる
let sampleFunc = hoge => hoge + 1;

// 引数がない場合、()は必須
let sampleFunc = () => console.log('Hello World');

// 複数式や文の場合、{}で囲む必要あり
let sampleFunc = (hoge, foo) => {
    let sampleValue = hoge * foo;
    return sampleValue;
}
```

# 引数
```javascript
const sampleFunc = (hoge, foo) => {
    const sampleValue = hoge + foo;
    return sampleValue;
}

// あふれた引数は無視される。今回は5が無視される
sampleFunc(2, 3, 4) // 5
```

## コールバック関数：関数の引数として渡された別の関数

```javascript
setTimeout(() => {
    console.log('3秒後に呼ばれます!');
}, 3000)

// コールバック関数を分けて宣言した場合
// 第2引数で指定した3000ミリ秒後に、第1引数のコールバック関数が呼び出される
const callback = () => { console.log('3秒後に呼ばれます!') };
setTimeout(callback, 3000)
```

## デフォルト引数

```javascript
const sampleFunc = (hoge = 3, foo = 2) => {
    const sampleValue = hoge + foo;
    return sampleValue;
}

// 引数を省略した場合、引数にはデフォルト値が入る
sampleFunc() // 5

// 引数がある場合、デフォルト引数は無視される
sampleFunc(30, 20) // 50 
```

## 引数の分割代入
 
```javascript
// userオブジェクト
const user = {
name: 'Sato',
age: '20'
}

// userオブジェクトからnameプロパティを分割代入
const sampleFunc = ({name}) => console.log(name);

// 分割代入しない場合
const sampleFunc = (user) => console.log(user.name);

// nameプロパティの値である'Sato'が引数として代入される
sampleFunc(user); // Sato
```

## 分割代入でpropsを受け取る

```javascript
// 親コンポーネントから渡されたprops
props {
    name: 'Sato',
    age: '20',
}

// 子コンポーネントであるuserコンポーネントでnameプロパティをpropsで受け取る
const User = (props) => <p>{props.name}</p>

// 以下のように書くことも可能
const User = ({ name }) => <p>{name}</p> 
```

# for...in文
for...in文は、オブジェクトから取り出したプロパティに対して順番不定でくり返し処理を実行する

```javascript
let user = {
    name: 'Sato',
    age: 20,
    heigth: 175
    weight: 60
}

for (let key in user) {
    console.log(key)
}
// name
//age
//height
//weight
```

# for...of文
for...of文は、反復可能オブジェクトに対して、定義した順番で値を反復処理する

```javascript
let items = ["aaa", "bbb", "ccc"]

for(let item of items) {
    console.log(item)
}
// aaa
// bbb
// ccc
```

# 配列

## 配列であるか判定する
Array.isArray(obj)を利用すると、指定したobj(オブジェクト)が配列であるかを真偽値で返す

```javascript
// 空の配列を宣言
const sampleArray = [];

// 空のオブジェクトを宣言
const sampleObject = {};

console.log(Array.isArray(sampleArray)); // true
console.log(Array.isArray(sampleObject)); // false
```

## 配列から要素を検索する
Array.indexOf()を使用すると、配列から指定した要素がどの位置にあるか取得できる

```javascript
// 配列sampleArrayIndexOfを宣言
const sampleArrayIndexOf = ["red", "blue", "green", "yellow", "red"]

// 最初に"red"とマッチするindexである0を返す
console.log(sampleArrayIndexOf.indexOf("red")); // 0

// マッチする要素が見つからない場合は-1を返す
console.log(sampleArrayIndexOf.indexOf("black")); // -1
```

Array.inclueds(arg)を利用すると、配列にargで指定した要素が含まれているか真偽値を返す

```javascript
// 配列sampleArrayIndexOfを宣言
const sampleArrayIncludes = ["red", "blue", "green", "yellow", "red"]

// "red"は配列に含まれているのでtrueを返す
console.log(sampleArrayIncludes.inclueds("red")); // true

// "black"は配列に含まれていないのでfalseを返す
console.log(sampleArrayIncludes.includes("black")); // false
```

### 配列の結合
```javascript
const sampleArray1 = ["a", "b"]
const sampleArray2 = ["c", "d"]

// Array.concat()を使用する
console.log(sampleArray1.concat(sampleArray2)) // ["a", "b", "c", "d"]

// ...Arrayを使用する
const newArray = [...sampleArray1, ...sampleArray2]
console.log(newArray); // ["a", "b", "c", "d"]

// Array.join(separator)を使用する
const sampleArrayDate = ["2023", "3", "19"];
console.log(sampleArrayData.join("/")); // 2023/3/19
```

### 配列のソート
破壊的メソッド：並び替えや要素の削除を行うことにより、元の配列そのものに変更を加えるメソッドをことを**破壊的メソッド**と言います。

```javascript
const sampleArrayStrSort = ["お", "う", "い", "え", "あ"];

// 昇順に並び替え
console.log(sampleArrayStrSort.sort()); // ["あ", "い", "う", "え", "お"];

// もとの配列要素の順番も変わっている
console.log(sampleArrayStrSort); // ["あ", "い", "う", "え", "お"];

// 比較関数を使用する場合
// aはbより小さいインデックスにソートする
function compareFunction(a, b) {
    return a - b;
}

const sampleArrayNumSort1 = [1, 4000, 30, 50, 200];

sampleArrayNumSort1.sort(compareFunction);

console.log(sampleArrayNumSort1) // [1, 30, 50, 200, 4000]

// 比較関数を使用しない場合
const sampleArrayNumSort2 = [1, 4000, 30, 50, 200];

sampleArrayNumSort2.sort(compareFunction);

console.log(sampleArrayNumSort1) // [1, 200, 30, 4000, 50]

// 元の配列を変更することなくArray.sort()する
const sampleArrayStrSort3 = ["お", "う", "い", "え", "あ"];

// スプレット構文を利用
console.log([...sampleArrayStrSort3].sort()); // ["あ", "い", "う", "え", "お"];

// 元の配列要素の順番には影響しない
console.log(sampleArrayStrSort3); // ["あ", "い", "う", "え", "お"];

// concat()を利用
console.log(sampleArrayStrSort3.concat().sort()); // ["あ", "い", "う", "え", "お"];

// 元の配列要素の順番には影響しない
console.log(sampleArrayStrSort3); // ["あ", "い", "う", "え", "お"];
```

配列を降順に並び替える場合は、Array.sort()をArray.reverse()に変更すれば良い

## 配列要素の削除
配列要素を削除する場合、Array.pop()、Array.shift()、Array.splice()を使用する
```javascript
const sampleArrayDelete = ["aaa", "bbb", "ccc"];

// Array.pop()は配列の最後の要素を削除する
sampleArrayDelete.pop();

// 元の配列の配列要素に影響する
console.log(sampleArrayDelete); // ["aaa", "bbb"];
``` 

```javascript
const sampleArrayDelete = ["aaa", "bbb", "ccc"];

// Array.shift()は配列の最初の要素を削除する
sampleArrayDelete.shift();

// 元の配列の配列要素に影響する
console.log(sampleArrayDelete); // ["bbb", "ccc"];
``` 

```javascript
const sampleArrayDelete = ["aaa", "bbb", "ccc"];

// Array.splice()は特定の配列要素を削除する
// 0番目(先頭)から2個の要素"aaa", "bbb"を削除する
sampleArrayDelete.splice(0, 2);

// 元の配列の配列要素に影響する
console.log(sampleArrayDelete); // ["ccc"];
``` 

```javascript
const sampleArrayDelete = ["aaa", "bbb", "ccc"];

// Array.splice()は特定の配列要素を削除する
// 0番目(先頭)から2個の要素"aaa", "bbb"を削除し、"ddd"を先頭に追加する
sampleArrayDelete.splice(0, 2, "ddd");

// 元の配列の配列要素に影響する
console.log(sampleArrayDelete); // ["ddd", "ccc"];
``` 

### 配列要素の追加
配列に要素を追加する場合、Array.push(arg)、Array.unshift(arg)を利用する

```javascript
const sampleArrayAdd = ["aaa", "bbb", "ccc"];

// Array.push()は最後に要素"ddd"を追加
sampleArrayAdd.push("ddd");

// 元の配列の配列要素に影響する
console.log(sampleArrayAdd); // ["aaa", "bbb", "ccc", "ddd"];
```

```javascript
const sampleArrayAdd = ["aaa", "bbb", "ccc"];

// Array.unshift()は最初に要素"ddd"を追加
sampleArrayAdd.unshift("ddd");

// 元の配列の配列要素に影響する
console.log(sampleArrayAdd); // ["ddd", "aaa", "bbb", "ccc"];
```

## 配列の高階関数
コールバック関数は引数として渡される関数、コールバック関数を引数で受け取る関数のことを高階関数と呼ぶ

### Array.forEach(callback)
Array.forEach(callback)は、配列における反復処理のためのメソッドです。
取り出した配列要素に対し、引数に渡されたコールバック関数で順番に処理する

コールバックが受け取る引数
・第1引数のvalueへ配列要素が渡される
・第2引数のindexへ0から始まるindex番号が渡される
・第3引数のarrayへ元の配列が渡される

```javascript
const sampleArrayForEach = [1, 2, 3, 4];

// 引数は配列の要素、index、元の配列
sampleArrayForEach.forEach((value, index, array) => {
    
    // 第1引数のvalueへ配列要素の1, 2, 3, 4が順番に渡される
    // 第2引数のindexへ0から始まる番号が渡される
    // 第3引数のarrayへ元の配列sampleArrayForEachが渡される

    console.log('value: ${value}, index: ${index}, array: ${array}')
    // value: 1, index:0, array: 1, 2, 3, 4
    // value: 2, index:1, array: 1, 2, 3, 4
    // value: 3, index:2, array: 1, 2, 3, 4
    // value: 4, index:3, array: 1, 2, 3, 4
```

### Array.map()
Array.map(callback)は配列における反復処理のためのメソッドです。
取り出された配列要素に対し、引数に渡されたコールバック関数で順番に処理する。

コールバックが受け取る引数
・第1引数のvalueへ配列要素が渡される
・第2引数のindexへ0から始まるindex番号が渡される
・第3引数のarrayへ元の配列が渡される
(第2引数と第3引数は利用しない場合、省略可能)

```javascript
const sampleArrayForMap = [2, 4, 6, 8];

    // 第1引数のvalueには1つ1つ取り出された配列要素を渡す
    // 第2引数、第3引数は利用しないので省略
    sampleArrayForMapResult = sampleArrayForMap.map((value) => {
        return value * value;
    })

    console.log(sampleArrayForMapResult); // [4, 16, 36, 64]

    // 元の配列要素に影響しない
    console.log(sampleArrayForMap); // [2, 4, 6, 8]
```

### Array.filter()
Array.filter(callback)は配列における反復処理のためのメソッドです。
取り出された配列要素に対し、引数に渡されたコールバック関数で順番に処理する。

コールバックが受け取る引数
・第1引数のvalueへ配列要素が渡される
・第2引数のindexへ0から始まるindex番号が渡される
・第3引数のarrayへ元の配列が渡される
(第2引数と第3引数は利用しない場合、省略可能)

```javascript
const sampleArrayForFilter = [3, 5, 7, 9];

    // 第1引数のvalueには1つ1つ取り出された配列要素を渡す
    // 第2引数、第3引数は利用しないので省略
    // 3で割り切りれる配列要素が取り出される
    sampleArrayForFilterResult = sampleArrayForFilter.filter((value) => {
        return value % 3 === 0;
    })

    console.log(sampleArrayForFilterResult); // [3, 9]

    // 元の配列要素に影響しない
    console.log(sampleArrayForFilter); // [3, 5, 7, 9]
```

### Array.find()
Array.find(callback)は配列における反復処理のためのメソッドです。
取り出された配列要素に対し、引数に渡されたコールバック関数で順番に処理する。

コールバックが受け取る引数
・第1引数のvalueへ配列要素が渡される
・第2引数のindexへ0から始まるindex番号が渡される
・第3引数のarrayへ元の配列が渡される
(第2引数と第3引数は利用しない場合、省略可能)

```javascript
const sampleArrayForFind = [9, 12, 15, 18];

    // 第1引数のvalueには1つ1つ取り出された配列要素を渡す
    // 第2引数、第3引数は利用しないので省略
    // 配列要素を最初から取り出していき、一番最初に3で割り切れる数が出るまで繰り返す
    sampleArrayForFindResult = sampleArrayForFind.find((value) => {
        return value % 3 === 0;
    })

    console.log(sampleArrayForFindResult); // [9]

    // 元の配列要素に影響しない
    console.log(sampleArrayForFind); // [9, 12, 15, 18]
```

### Array.findIndex()
Array.findIndex(callback)は配列における反復処理のためのメソッドです。
取り出された配列要素に対し、引数に渡されたコールバック関数で順番に処理する。

コールバックが受け取る引数
・第1引数のvalueへ配列要素が渡される
・第2引数のindexへ0から始まるindex番号が渡される
・第3引数のarrayへ元の配列が渡される
(第2引数と第3引数は利用しない場合、省略可能)

```javascript
const sampleArrayForFindIndex = [9, 12, 15, 18];

    // 第1引数のvalueには1つ1つ取り出された配列要素を渡す
    // 第2引数、第3引数は利用しないので省略
    // 配列要素を最初から取り出していき、3で割り切れる要素がある場合、その配列番号を返す
    // 配列要素を最初から取り出していき、3で割り切れる要素がない場合、-1を返す
    sampleArrayForFindIndexResult = sampleArrayForFindIndex.findInex((value) => {
        return value % 3 === 0;
    })

    console.log(sampleArrayForFindIndexResult); // 0

    // 元の配列要素に影響しない
    console.log(sampleArrayForFindIndex); // [9, 12, 15, 18]
```

### Array.every()
Array.every(callback)は配列における反復処理のためのメソッドです。
取り出された配列要素に対し、引数に渡されたコールバック関数で順番に処理する。

コールバックが受け取る引数
・第1引数のvalueへ配列要素が渡される
・第2引数のindexへ0から始まるindex番号が渡される
・第3引数のarrayへ元の配列が渡される
(第2引数と第3引数は利用しない場合、省略可能)

```javascript
const sampleArrayForEvery = [9, 12, 15, 18];

    // 第1引数のvalueには1つ1つ取り出された配列要素を渡す
    // 第2引数、第3引数は利用しないので省略
    // 配列要素を最初から取り出していき、全ての要素が3で割り切れる場合、trueを返す
    // 配列要素を最初から取り出していき、1つでも3で割り切れない要素がある場合、falseを返す
    sampleArrayForEvery = sampleArrayForEvery.every((value) => {
        return value % 3 === 0;
    })

    console.log(sampleArrayForEveryResult); // true

    // 元の配列要素に影響しない
    console.log(sampleArrayForEvery); // [9, 12, 15, 18]
```

### Array.some()
Array.some(callback)は配列における反復処理のためのメソッドです。
取り出された配列要素に対し、引数に渡されたコールバック関数で順番に処理する。

コールバックが受け取る引数
・第1引数のvalueへ配列要素が渡される
・第2引数のindexへ0から始まるindex番号が渡される
・第3引数のarrayへ元の配列が渡される
(第2引数と第3引数は利用しない場合、省略可能)

```javascript
const sampleArrayForSome = [9, 12, 15, 18];

    // 第1引数のvalueには1つ1つ取り出された配列要素を渡す
    // 第2引数、第3引数は利用しないので省略
    // 配列要素を最初から取り出していき、15で割り切れる要素がある場合、trueを返す
    // 配列要素を最初から取り出していき、15で割り切れる要素がない場合、falseを返す
    sampleArrayForSome = sampleArrayForSome.every((value) => {
        return value % 15 === 0;
    })

    console.log(sampleArrayForSomeResult); // true

    // 元の配列要素に影響しない
    console.log(sampleArrayForSome); // [9, 12, 15, 18]
```

### Array.reduce()
Array.some(callback, initialValue)は配列における反復処理のためのメソッドです。
前回の値accumulatorと現在の値currentValueの配列要素を受け取り、コールバックで関数で処理された値を次の値として返す

コールバックが受け取る引数
・第1引数のaccumulatorへ前回の値が渡される
・第2引数のcurrentValueへ現在の値が渡される
・第3引数のcurrentIndexへ現在currentValueとして処理されている要素のindexが渡される
・第4引数のarrayへ元の配列が渡される
(第3引数と第4引数は利用しない場合、省略可能)

```javascript
const sampleArrayForReduce = [0, 1, 2, 3];
const initialValue = 0;

    // 第1引数のaccumulatorには前回の値を渡し、第2引数のcurrentValueには現在の値を渡す
    // 第3引数、第4引数は利用しないので省略
    sampleArrayForReduceResult = sampleArrayForReduce.reduce((accumulator, currentValue) => {
        console.log("accumulator:", accumulator, "currentValue:", currentValue)
        // accumulator: 0 ← 初期値(initialValue) currentValue: 0 ← 配列の第1要素(0)
        // accumulator: 0 ← 0 + 0               currentValue: 1 ← 配列の第2要素(1)
        // accumulator: 1 ← 0 + 1               currentValue: 2 ← 配列の第3要素(2)
        // accumulator: 3 ← 1 + 2               currentValue: 3 ← 配列の第4要素(3)

        return accumulator + currentValue;
    }, initialValue);

    console.log(sampleArrayForReduceResult); // 3 + 3 = 6
```