【JavaScript】基本的な書き方

JavaScriptは、ブラウザを「動かす」ためのプログラム言語。


# 基本

#### Javascriptを書く場所

scriptタグは、bodyタグの閉じタグのすぐ上に書く。
（'use strict'と書いておくと、ブラウザが厳密なエラーチェックをしてくれる）

```index.html
<script>
  'use strict';
  //ここにコードを書きます
</script>
```
外部ファイルとして読み込む場合はこのように。

```index.html
<script src="main.js"></script>
```


#### エラーなどの確認方法（コンソールの開き方）

Chromeブラウザで、右クリック→検証でデベロッパーツールを表示し、コンソール [Console] を開く。（MACのショートカットキーはCommand＋Option＋I）


#### コンソールに文字列を出力

```console.log('文字列');```

- `\` ... 直後の記号を文字列として読み込ませる
- `\n` ... 文字列に改行を入れる
- `\t` ... 文字列にタブを入れる
- 文字列の連結は、`'文字列' + '文字列'`。
- 数値からなる文字列は数値として計算される（"+"だけは例外で、文字列の連結と見なされる）。


#### 算術演算子

- `+` ... 足す
- `-` ... 引く
- `*` ... 掛ける
- `/` ... 割る
- `%` ... 割った余り
- `**` ... べき乗

※特殊な書き方
`i = i + 1` と `i += 1` と `i++` は同じ意味。


#### 比較演算子

- `a > b` ... aはbより大きい
- `a < b` ... aはbより小さい
- `a >= b` ... aはb以上
- `a <= b` ... aはb以下
- `a === b` ... aはbと等しい（厳密等価演算子）※等価演算子は`==`
- `a !== b` ... aはbと異なる


#### 真偽値

- `Boolean()` ... 値をtrue/falseで評価
- 値自体のtrue/false
    - false ... false, 0, null, undefined, 空文字列
    - true ... それ以外


#### データ型

- `typeof()` ... データ型を確認
- `parseInt('数値', 10)` ... 10進数の整数に変換
- データ型の種類
    - `Number`...数値（5, 3.4, -30）
    - `String`...文字列（'hello', "世界"）
    - `Boolean`...真偽値（true, false）
    - `Null`... 存在しない、無効をあらわす値（null）
    - `Undefined`...未定義をあらわす値（undefined）
    - `BigInt`...大きな数値をあつかう値
    - `Symbol`...シンボル値
    - `Objec`...オブジェクト（{a:3, b:5}）



# 定数・変数

#### 定数を宣言（const）

定数は、値を格納しておく箱のようなもの。
定数は値の再代入ができない。

`const 定数名 = 値;`

#### 変数を宣言（let）

定数と同じ書き方をする。値の再代入が可能。

```main.js
let 変数名 = 値;

//変数を再代入
変数名 = 値;
```

※定数/変数は大文字/小文字が区別される。
※数字から始まる変数名はつけられない。

#### 文字列の中に変数を入れ込む（${ }）

文字列の中に変数を入れ込む時は、"${}（テンプレートリテラル）"を使い、**バッククオート**で囲う。
`hello ${変数}`


#### 有効範囲（スコープ）

定数や変数がブロック内で宣言された場合、その定数や変数はブロックの中でだけ有効。（ブロック ... {}）
ブロックの外で宣言された定数はグローバルスコープと呼ばれ、全ての範囲で有効。



# 条件分岐


#### 条件分岐（if）

もし〜だったらこの処理をする。

```main.js
if (条件式) {
  trueだった時の処理;
} 
```
"else"を使ってfalseだった時の処理を指定したり、さらに"else if"を使って複数の条件を入れることも可能。

例）scoreが80点以上だったら'Great!'、60点以上だったら'Good.'、それ以外だったら'OK...'をconsoleに表示。
```main.js
const score = 50;

if (score >= 80) {
  console.log('Great!');
} else if (score >= 60) {
  console.log('Good.');
} else {
  console.log('OK...');
}
```

#### 条件演算子

コードをより短く書くことができるが、わかりづらくなる時もあるので注意して使う。

`条件式 ? trueの処理 : falseの処理`

書き方の例。

```main.js
const score = 50;

score >= 80 ? console.log('Great!') : console.log('OK...');
```
上記のような場合は下記のように省略することができる。（コメントで教えていただきました。ありがとうございます）

```main.js
console.log(score >= 80 ? 'Great!' : 'OK...');
```




#### 論理演算子

- `&&` ... なおかつ（ AND ）
- `||` ... もしくは（ OR ）
- `!` ... 〜ではない（ NOT ）

```main.js
if (条件1 && 条件2) {
    処理;
}
```

#### 条件分岐（swicth）

"==="を使った複数条件の分岐処理を行う場合は、switch文を使う。

```main.js
switch (式or変数) {
    case '値1':
        式の結果が値1に等しい場合の処理;
        break;
    case '値2':
        式の結果が値2に等しい場合の処理;
        break;
    default:
        どれにも該当しない時の処理;
}
```



# 繰り返し処理

#### 繰り返し処理（for）

繰り返し処理を実行。

```main.js
for (カウンタ変数定義と初期化; 繰り返し回数の指定; カウンタ加算幅) {
    繰り返す処理;
}
```
例）
```main.js
for(let i = 0; i < 3; i++){
    console.log(`変数 i の値は${i}`);
}
```

### 繰り返し処理（for in）

```main.js
for (変数名 in オブジェクト){
    繰り返す処理
}
```
例）
```main.js
const fruit = {orange:170, apple:90, lemon:110};
for (let i in fruit){
    console.log("fruit." + i + ' = ' + fruit[i]);
}
```

### 繰り返し処理（for of）

```main.js
for (変数名 of 反復可能オブジェクト){
    繰り返す処理
}
```
例）
```main.js
let menu = ['紅茶','コーヒー','ケーキ'];
for (let m of menu){
    console.log(m);
}
```


#### ループ処理（while）

条件に当てはまる間、処理を実行。

```main.js
while (条件) {
    処理;
}
```

#### ループ処理（do while）

最初から条件に当てはまらなくても処理を1度実行する場合。

```main.js
do {
    処理;
} while (条件)
```
例）

```main.js
do {
    console.log (`${hp} HP left!`);
    hp -= 15;
} while (hp > 0);
```

#### or文やwhile文の特定の回だけスキップ（continue）

```main.js
for (let i = 1; i <= 10; i++) {
    if (条件) {
        continue;
    }
    処理;
}
```

#### for文やwhile文の処理を途中で止める（break）

```main.js
for (let i = 1; i <= 10; i++) {
    if (条件) {
        break;
    }
    処理;
}
```



# 関数（function）

関数を定義し、実際に呼び出して利用することで、似たような処理を何度も書かなくて済むようになる。

```main.js
// 関数の定義
function 関数名(){
    任意の処理
    return 戻り値;
}
// 関数の呼び出し
関数名();
```
例）
```main.js
function sum(x,y){
    let ans = x + y;
    return ans;
}
window.alert(sum(3,4));
```

#### 引数を使う

引数は、関数に渡して、処理の中でその値を使うことができるようにするもの。

```main.js
function 関数 (引数 = 'デフォルト値') {
    引数を利用した処理;
}
```
※デフォルト値を入れない場合は()の中に引数だけ入れる。
※引数が0のときは()だけ書く ```() =>```
※引数が1つのときは()を省略できる ```引数 => {```

#### 値を返す（return）

値や文字列などを関数の外に返す処理。

```main.js
function sum(a, b, c) {
    return a + b + c;
}
```
※関数内でreturnと書くと、その時点で値が戻されて、それ以降の処理は実行されない。

#### 関数宣言

function文を用いて関数を宣言する方法。

```main.js
function 関数(仮引数, 仮引数, ...) {
  処理;
  処理;
  return 返り値;
}
//呼び出す時
関数(実引数, 実引数, ...);
```
書き方の例。

```main.js
function sum(a, b, c) {
  return a + b + c;
}
```

#### 関数式

変数（もしくは定数）に関数を値として代入し、後からその変数を呼び出すことで関数を間接的に利用する方法。

```main.js
const 定数名 = function(仮引数, 仮引数, ...) {
  処理;
  処理;
  return 返り値;
}

//呼び出す時
定数名(実引数, 実引数, ...);
```
書き方の例。

```main.js
const sum = function(a, b, c) {
    return a + b + c;
}
```

#### アロー関数

- 関数式をより短く書くことができる書き方。
- 多くの場合、関数の引数に設定するコールバック関数(名前のない関数)として使う。

```main.js
(引数) => {
    処理
    return 戻り値;  //returnで返すだけの処理ではreturn省略可
}
```
例）上の関数式をアロー関数で書く場合。
```main.js
const sum = (a, b, c) => a + b + c;
```



# 配列

配列を使うと、同じ種類の複数のデータをまとめて登録しておくことができる。

#### 配列を登録

```main.js
const scores = [80,90,40];
console.log(scores); //出力結果：80,90,40
```

#### 配列の一部の値を出力

配列の中の一部のデータを拾いたい場合は、[ ]の中にインデックスの数字を入れる。（0番目から始まるので注意）

```main.js
console.log(scores[0]); //出力結果：80
```

#### 配列の一部の値を変更

constで定義した定数への再代入はできないが、配列の要素への代入は可能。

```main.js
scores[0] = 70;
```

#### 配列の要素数を取得（length）

```main.js
console.log(scores.length);
```
forと組み合わせて使う。（"score 0: 80"...のように配列のすべてを表示する）

```main.js
for(let i = 0; i < scores.length; i++) {
    console.log(`score ${i}: ${scores[i]}`);
}
```

#### 配列の要素の追加と削除

- `push()` ... 配列の先頭に要素を追加（まとめて複数可能）
- `unshift()`  ... 末尾に要素を追加（まとめて複数可能）
- `pop()`  ... 先頭から要素を削除（1つづつ）
- `shift()`  ... 末尾から要素を削除（1つづつ）
- `splice(変化が開始する位置, 削除数(, 追加する要素))` ... 要素を削除、置き換え、追加

#### 配列の中で配列を展開（スプレッド構文）

配列の中に別の配列の中身を展開したい場合は、スプレット構文 `...配列` を使う。

```main.js
const otherScores = [10, 20];
const scores = [80,90,40, ...otherScores];
```

※スプレッド構文は、配列の値をコピーしたい時にも使える。（配列は値の格納された場所であり、そのまま代入すると値が変わってしまうため）


#### 配列の値を分割して定数に設定（分割代入）

配列に入っている値を、分割して別々の定数に代入する。

```main.js
const[a, b, c, d] = scores;
```

#### 分割代入した残りの値を別の配列に格納（レスト構文）

分割代入と一緒に使うと、こちらで割り当てた以外の要素をここで指定した名前の配列に格納してくれる。

```main.js
const[a, b, ...others] = scores;
```

#### 値の交換

分割代入は値の交換にもよく使われる。

```main.js
[x, y] = [y, x];
```

#### 配列の全ての要素に対して処理をする（forEach）

通常繰り返し処理にはfor文を使うが、配列にfor文の操作をする時は、forEachを使うとシンプルに書くことができる。

    配列.forEach( コールバック関数(functon)による処理 )

書き方の例。

```main.js
const scores = [80,90,40];

scores.forEach((score, index) => {
  console.log(`Score${index}: ${score}`);
})
//出力結果：Score
```

#### 配列に処理をした結果を別の配列として取得（map）

    const 新しい配列 = 配列.map( コールバック関数(functon)による処理 )

書き方の例。配列pricesの各要素をpriceで受け取り、そこに20を足した上で別の配列updatedPricesに格納する。

```main.js
const prices = [180, 190, 200];

const updatedPrices = prices.map((price) => {
  return price + 20;
});

//引数が1つの場合は引数の()は省略可能
//return1行の場合は省略可能
//なので、上記は以下のように省略できる
const updatedPrices = prices.map(price => price + 20);
```

#### 配列の中から条件に合う要素だけを取得（filter）

    const 新しい配列 = 配列.filter( コールバック関数(functon)で指定した条件 )

書き方の例。配列numberの中から、偶数のみを別の配列evenNumbersに格納する。

```main.js
const number = [1, 4, 7, 8, 10];

const evenNumbers = number.filter(number => {
  if (number % 2 === 0) {
    return true;
  } else {
    return false;
  }
});

//ifの条件式自体をreturnすればいいので、
//上記は以下のように省略できる
const evenNumbers = number.filter(number => number % 2 === 0);
```



# オブジェクトの基本

オブジェクトとは変数と関数の集合体で、情報を入れられて管理するための箱のようなもの。



以下のように、配列の値に名前（キー）をつけて管理する。

```
const 配列 {
  キー: 値,
  キー: 値,
}
```
書き方の例。

```main.js
const point = {
  x: 100, //100という値にxという名前をつけて配列に入れる
  y: 180, //180という値にyという名前をつけて配列に入れる
}
```
オブジェクトの一つ一つの要素をプロパティと呼ぶ。

#### オブジェクトのプロパティにアクセス

- オブジェクトのプロパティは、`配列.キー` もしくは `配列['キー']` で表す。
- すでにあるプロパティを記述すると値が上書きされ、存在しないプロパティを記述すると値が追加される。
- プロパティを削除する時は、`delete` を使う。

書き方の例。

```main.js
const point = {
  point.x = 120; //xの値を120に変更
  point.z = 90; //値の追加（新しいキーで値を設定）
  delete point.z = 90; //値の削除
}
```
入れ子も可能。
```main.js
let user = {
    id: 1,
    name: 'hoge',
    info:{
        tel: '888-88-8888',
        mail: 'fuga@js.co.jp'
    }
}
window.alert(user.name + '\n' + user.info.mail)
```


#### 配列の中で別の配列のオブジェクトを展開

配列を別の配列の中に展開する時に使うスプレッド構文（...配列名）は、オブジェクトを展開する時にも使える。

書き方の例。配列pointの中に、別の配列otherPropsを展開する。

```main.js
const point = {
        x: 100,
        y: 180,
        ...otherProps, //otherProps...展開する配列
    }
```

また、分割代入やレスト公文も、オブジェクトでも同様に使うことができる。

#### オブジェクトのキーのみを取得（Object.keys）

    Object.keys(配列)

書き方の例。オブジェクトのプロパティを列挙する。

```main.js
const keys = Object.keys(point);

keys.forEach(key => {
console.log(`Key: ${key} Value: ${point[key]}`)
    })
//出力結果：Key: x Value: 100, ...
```
※文字列で取得されているので、`配列.キー` ではなく `配列['キー']` の書き方を使って文字列を入れる。

#### 複数のオブジェクトを配列に入れて管理

書き方の例。pointsという配列を作り、その中に要素として複数のオブジェクトを入れる。

```main.js
const points = [
  {x: 30, y: 20},
  {x: 10, y: 50},
  {x: 40, y: 40},
];

//※2番目のプロパティのyの値を出力（0番目から始まるので[1]）
console.log(points[1].y); //出力結果：50
```



# 文字列の操作

#### 文字数を取得

文字列を取得する時は、以下のように書く。

    文字列.length

書き方の例。定数strの文字列'Hello!'の文字数を取得する。

```main.js
const str = 'Hello!';
console.log(str.length); //出力結果：6
```

#### 部分文字列を取得

部分的に文字列を取得する場合は、以下のように書く。

```
文字列.substring(開始位置, 終了位置)
//もしくは
文字列.substr(文字数)
```
書き方の例。定数strの文字列'Hello!'の2(3)番目から3(4)番目の文字列を取得する。

```main.js
const str = 'Hello!';
console.log(str.substring(2, 4)); //出力結果：ll

//文字列に対して配列のような記法を使うと、個々の文字が取得できる
console.log(str[1]); //出力結果：e
```

#### 配列の要素を文字列として結合（join）

()の中に文字列を入れると、その文字列を挟んで結合する。

    配列.join(文字列)

書き方の例。配列dを"/"を挟んで文字列として結合。

```main.js
const d = [2020, 12, 5]
console.log(d.join('/')); //出力結果：2020/12/5
```

#### 文字列を分割（split）

文字列を指定した区切り文字のところで分割する。

    文字列.split(分割する文字列)

書き方の例。定数の文字列を":"のところで分割し、その返り値を分割代入を使って別々の定数に代入。

```main.js
const t = '23:45:17';

const [hour, minute, second] = t.split(":");

console.log(hour); //出力結果：23
console.log(minute); //出力結果：45
console.log(second); //出力結果：17
```

#### その他の文字列に関する命令

- `文字列.replace(置換する文字列, 置換後の文字列)` ... 文字列内の指定文字列を置換
- `文字列.toUpperCase()` ... 文字列を大文字に変換
- `文字列.toLowerCase()` ... 文字列を小文字に変換



# 数値の操作

#### 四捨五入/切り上げ/切り捨て

- `round()` ... 四捨五入
- `定数.toFixed(桁数)` ... 指定した桁数で四捨五入
- `ceil()` ... 小数点以下を切り上げ
- `Math.floor()` ... 小数点以下を切り捨て

#### 合計と平均を求める

Javascriptでは数値の合計や平均を求める命令はないので、forEachを使う。

書き方の例。

```main.js
const scores = [10, 3, 9]; //scoresという配列を設定

let sum = 0; // sumという変数を用意

scores.forEach(score => {
    sum += score;
})
//配列の合計を求める。forEachで配列scoresの全ての要素に対して処理をし、引数scoreとして配列scoresのそれぞれの値を渡して変数sumに足していく

const avg = sum /scores.length; 
//配列の平均を求める。lengthで求めた配列の要素数で合計を割る

console.log(sum); //出力結果：22
console.log(avg.toFixed(3)); //出力結果：7.333
```

#### ランダムな数値を生成

`Math.random()` ... 0以上1未満のランダムな数値を生成

0からnまでのランダムな整数値を生成。

    Math.floor(Math.random() * (n + 1))

min から max までのランダムな整数値を生成。

    Math.floor(Math.random() * (max + 1 - min)) + min

書き方の例。1から6までのランダムな整数を生成。

```main.js
console.log(Math.floor(Math.random() * (6 + 1 - 1)) + 1);
```



# 日時のデータの操作

#### 現在日時を取得

- `new Date()` ... 現在日時（）
- `getTime()` ... 協定世界時（UTC）

#### 特定の日時のデータを設定

`new Date()` に引数を渡す。（年と月は必須）


#### 日時の一部をデータとして取り出す

- `getFullYear()` ... 年
- `getMonth()` ... 月（0〜11）
- `getDate()` ... 日（1〜31）
- `getDay()` ... 曜日（0〜6）
- `getHours()` ... 時間（0〜23）
- `getMinutes()` ... 分（0〜59）
- `getSeconds()` ... 秒（0〜59）
- `getMilliseconds()` ... ミリ秒（0〜999）

書き方の例。

```main.js
const d = new Date(1990, 7, 15);

console.log(`${d.getMonth() + 1}月 ${d.getDate()}日`); // 出力結果：8月 15日
```


#### 日時のデータを変更する

後から日付を操作したい場合は、`set` で始まる命令を使う。

書き方の例。dの日付のデータを10月2日に変更する。

```main.js
const d = new Date(1990, 7, 15);

d.setMonth(9,2); //データを変更

console.log(`${d.getMonth() + 1}月 ${d.getDate()}日`); //出力結果：10月2日
```
書き方の例。dの日付のデータを3日後に変更する。

```main.js
const d = new Date(1990, 7, 15);

d.setDate(d.getDate() + 3); //データを変更

console.log(`${d.getMonth() + 1}月 ${d.getDate()}日`); //出力結果：8月 18日
```



# ダイアログを出す

#### 警告のダイアログ

文字列と「OK」ボタンを表示する。

    alert('文字列');

#### 確認のダイアログ

文字列と「キャンセル」/「OK」ボタンを表示する。

    confirm('文字列');

書き方の例。OKを押した場合は「削除しました」、キャンセルを押した場合は「削除しました」を出力する。

```main.js
const answer = confirm('削除しますか？');

if (answer) {
    console.log('削除しました');
} else {
    console.log('キャンセルしました');
}
```



# タイマー機能

#### 一定時間ごとに特定の処理を繰り返す（setInterval）

```
setInterval(実行する関数, 処理間隔);

//止める時
clearInterval(タイマーの識別子);
```

書き方の例。現在時刻を表示する関数showTime()の処理を、1秒ごとに繰り返す。

```main.js
function showTime() {
  console.log(new Date());
}

setInterval(showTime, 1000);
//関数の返り値ではなく関数を引数として渡すため、showTimeの後ろに"()"は付けない
//1000ミリ秒 = 1秒
```
さらに `clearInterval()` を使い、showTime()が3回実行された時に止める。

```main.js
let i = 0; //カウンター用の定変

function showTime() {
  console.log(new Date());
  i++; //カウンターを増やす
  if (i > 2) {
    clearInterval(intervalid);
  } //iの値が2より大きくなったら処理が止まるようにする 
}

const intervalid = setInterval(showTime, 1000);
//setInterval()の返り値が必要になるので、それを定数intervalIdに代入（タイマーの識別子）
```


#### 一定時間後に一度だけ処理をおこなう（setTimeout）

    setTimeout(関数function, 一定時間の指定[, 引数1, 引数2, …])

書き方の例。1秒後に1度だけ実行する。

```main.js
function showTime() {
  console.log(new Date());
}

setTimeout(showTime, 1000); //一度だけ実行
```
setTimeout()を連続して呼び出すことで、繰り返し処理を行うこともできる。

```main.js
function showTime() {
        console.log(new Date());
        setTimeout(showTime, 1000); //連続して呼び出す
    }

showTime();
```
`clearInterval()` を使い、showTime()が3回実行された時に止める。

```main.js
let i = 0; //カウンター用の定変

function showTime() {
  console.log(new Date());
  const timeoutId = setTimeout(showTime, 1000); //setInterval()の返り値が必要になるので、それを定数timeoutIdに代入（タイマーの識別子）
  i++; //カウンターを増やす
  if (i > 2) {
    clearTimeout(timeoutId); //setTimeout()の返り値である定数を入れる
  } //iの値が2より大きくなったら処理が止まるようにする 
}

showTime();
```



# 例外処理

例外処理とは、エラーなどの想定外の事態に対処する処理のこと。

#### try…catch文

```
try {
  処理; // 例外が起きそうな場所をtryで囲う
}
catch(e) { //catchに引数を渡すと、その例外の情報を扱うことができる
  例外が起きた時の処理;
}
```
書き方の例。エラーが起きたらエラー情報を出力し、止まらずに後の処理も実行する。

```main.js
const name = 3;

try {
  console.log(name.toUpperCase()); //数値に対して文字列を扱う関数を実行しようとし、エラーが起きる
} catch (e) {
  console.log(e); //出力結果：TypeError: name.toUpperCase is not a function
}

console.log('Finish!'); //出力結果：Finish!
```


# クラス

**クラス**（テンプレートのようなもの）を宣言し、それを使ってオブジェクトを生成し（**インスタンス**）利用することができる。

オブジェクトでは、プロパティの値として関数を持たせることもできる。（関数をプロパティの値にした場合、その関数を**メソッド**と呼ぶ）

#### クラスを宣言

`constructor() { }` は、インスタンスを生成するときに実行したい処理や設定を追加するための機能。

```
class クラス名 {
  constructor(引数) {
    this.キー: 引数;
    this.キー: 値;
  }
    関数() { ... },
}
```

書き方の例。Postというクラスを宣言した後に、postsの中に2つのインスタンスを生成し、show関数を呼び出して出力する。

`new クラス名()` は、クラスからオブジェクトを生成するための機能。

```main.js
class Post { //クラス名の先頭は大文字
  constructor(text) { //プロパティを初期化
    this.text = text; //インスタンスによって異なる値を入れる場合、constructor()に引数を渡すようにする
    this.likeCount = 0; //同じオブジェクト内のプロパティにアクセスするにはthisを使う
  }
  show() {
    console.log(`${this.text} - ${this.likeCount}いいね`);
  }
}

const posts = [
  new Post('JavaScriptの勉強中...'),
  new Post('プログラミング楽しい！'),
]; //インスタンスを作成

posts[0].show(); //出力結果：JavaScriptの勉強中... - 0いいね
posts[1].show(); //出力結果：プログラミング楽しい！ - 0いいね
}   
```


#### 静的メソッド

静的メソッドとは、インスタンスを生成しなくてもオブジェクトから直接呼び出せるメソッドのこと。（読み取り専用の用途で使う）
※ `this` はインスタンス自身を表すため、静的メソッドで使うことはできない。

クラスから直接呼び出すには `static` を使う。

```
class クラス名 {
  static メソッド名(){
    処理
  }
}
```
書き方の例。クラス自体の説明を出力する。

```main.js
class Post {
  static showInfo()  {
    console.log('Post class version 1.0');
  }
}
Post.showInfo(); //出力結果：Post class version 1.0
```

#### クラスを継承

親クラスの内容を引き継いだ子クラスを作成することを継承という。
クラスの継承を行うには `extends` を使用する。

```
class クラス名 extends 親クラス名 {
  小クラス独自の処理;
}
```
書き方の例。

```main.js
//親クラス
class Post {
  constructor(text) {
    this.text = text;
    this.likeCount = 0;
  }
  show() {
    console.log(`${this.text} - ${this.likeCount} いいね`);
  }
  like() {
    this.likeCount++;
    this.show();
  }
}
//子クラス
class SponsoredPost extends Post {
  constructor(text, sponsor) {
    super(text); //親クラスのconstructor()を呼び出す
    this.sponsor = sponsor;
  }
  show() {
    super.show(); //親クラスのshow()メソッドを使う
    console.log(`... sponsored by ${this.sponsor}`);
  }
}

const posts = [
  new SponsoredPost('3分動画でマスターしよう', 'dotgate'),
];

posts[0].show(); //出力結果3分動画でマスターしよう - 0 いいね ... sponsored by dotgate
posts[0].like(); //出力結果3分動画でマスターしよう - 1 いいね ... sponsored by dotgate
```
※小クラスでthisを使うには、`super()` で親クラスのconstructor()を呼び出す。
※小クラスで親クラスのメソッドを使うには、`super.メソッド名()` のように書く。



# DOMとは

DOM（Document Object Model）とは、JavaScriptでHTMLの要素を操作するための仕組みのこと。
DOM は `document` という特殊なオブジェクトで扱うことができる。
DOMでは、HTMLの中にあるすべてを「ノード」という単位で区切る（html、body、h1、pといったHTMLタグや、コメント、属性、テキストすべてがノード）。


#### 要素を取得するメソッド

- `.getElementById()` ... 特定のid属性を持つ要素を取得
- `.querySelector()` ... 特定のCSSセレクタの最初の1つの要素を取得
- `.querySelectorAll()[n]` ... 特定のCSSセレクタのn番目の要素を取得
- `.getElementsByTagName()` ... 特定のタグ名を持つ要素を取得
- `.getElementsByClassName()` ... 特定のclass属性を持つ要素を取得
- `.getElementsByName()` ... 特定のname属性の値を持つ要素を取得

【要素の内容の属性】
 - `.textContent` ... 要素のテキスト情報を表す
 - `.title` ... 要素に関する補助的な情報（hoverすると表示される）
 - `.item(インデックス)` = `children[0];` ... 要素に関する補助的な情報


例）#targetというid属性を持つ要素のテキストを変える。
```main.js
document.getElementById('target').textContent = 'Changed!'; //idの頭に"#"は不要
```

例）すべてのp要素のテキストを「n番目のpです」に変える。
```main.js
function update() {
  document.querySelectorAll('section > p').forEach((p, index) => {
    p.textContent = `${index}番目のpです`;
});
```
例）要素を取得（getElementById、getElementsByTagName）
```html:index.html
<p id="place">東京</p>
<button onClick="getElement();">要素を取得</button>
```
```Javascript:main.js
function getElement(){
    // id属性の値を指定して要素ノードを取得(getElementById)
    let element = document.getElementById('place');
    console.log(element.textContent);
    // タグ名を指定して要素ノードを取得(getElementsByTagName)
    elements = document.getElementsByTagName('p');
    let len = elements.length;
    for (let i = 0; i < len; i++){
        console.log(elements.item(i).textContent); //pタグのすべてのノードを出力
    }		    
}
```
例）要素を取得してスタイルを適用（getElementsByClassName）
```Javascript:main.js
// class属性の値を指定して要素ノードを取得(getElementsByClassName)
let elements = document.getElementsByClassName('button');
let len = elements.length;
for (let i = 0; i < len; i++){
    elements.item(i).style.border="4px solid #ffffff"; //.buttonのノードにスタイルを適用
}
```
例）ラジオボタンで要素を取得（getElementsByName）
```html:index.html
<label><input type="radio" name="hobby" value="Sports">Sports</label>
<label><input type="radio" name="hobby" value="Music" checked>Music</label>
<label><input type="radio" name="hobby" value="Travel">Travel</label>

<button onClick="getElements();">要素を取得</button>
```
```Javascript:main.js
function getElements(){
    let elements = document.getElementsByName('hobby');
    let len = elements.length;
    for (let i = 0; i < len; i++){
        if (elements.item(i).checked){
            console.log(elements.item(i).value + ' is checked');
        }
    }
}
```
  

#### DOM ツリーの階層関係から要素を取得

- `.childNodes()` ... 全ての子Nodeを取得
    - `.children()` ... 要素Nodeのみ
- `.firstChild()` ... 最初の子Nodeを取得
- `.lastChild()` ... 最後の子Nodeを取得
- `.parentNode()` ... 親Nodeを取得
- `.previousSibling()` ... 1つ前の兄弟Nodeを取得
    - `.previousElementSibling()` ... 要素Nodeのみ
- `.nextSibling()` ... 1つ後の兄弟Nodeを取得
    - `.nextElementSibling()` ... 要素Nodeのみ



# イベントに合わせて実行（addEventListener）

イベントに合わせて実行させる関数を登録するためのメソッド。

```
element.addEventListener(イベント, 関数, オプション);
```

#### イベントの種類（addEventListener()の第1引数）
- `load`... Webページの読み込みが完了した時（画像などのリソースすべて含む
- `DOMContentLoaded`...Webページが読み込みが完了した時に発動（画像などのリソースは含まない）
- `click` ... マウスボタンをクリックした時
- `dblclick` ... マウスボタンをダブルクリックした時
- `mousemove` ... マウスボタンを押している時
- `mouseup`... マウスボタンを離した時
- `mousemove`... マウスカーソルが移動した時
- `keydown` ... キーボードのキーを押した時
- `keyup`... キーボードのキーを離した時
- `keypress`... キーボードのキーを押している時
- `change`... フォーム部品の状態が変更された時
- `submmit`... フォームのsubmitボタンを押した時
- `scroll`... 画面がスクロールした時に発動


#### マウスボタンをクリックした時に実行（click）

例）#btnがクリックされた時に関数を実行する
```javascript:main.js
var btn = document.getElementById('btn');
btn.addEventListener('click', function() {
    console.log('クリックされました！');
}, false);
```
例）buttonがクリックされると#targetのテキストが変わるようにする
```javascript:main.js
document.querySelector('button').addEventListener('click', () => {
  document.getElementById('target').textContent = 'Changed!';
  }
);
```

#### マウスカーソルの座標を取得（mousemove）

関数に引数を渡すと、ブラウザがイベントに関する情報をセットして渡してくれる。引数はイベントオブジェクトと呼ばれ、慣習的に"e"がよく使われる。

例）マウスカーソルのX座標とY座標を出力
```main.js 
document.addEventListener('mousemove', e => {
  console.log(e.clientX,e.clientY);
});
```

#### キーボードで押されたボタンを取得（keydown）

例）キーボードで押したキーを出力。
```main.js 
document.addEventListener('keydown', e => {
  console.log(e.key);
});
```


#### フォームに関するイベントの種類

- `focus` ... フォーカス
- `blur` ... フォーカスを外す
- `input` ... 内容が更新
- `change` ... 更新が確定
- `submit` ... 送信


#### 入力されたテキストの文字数を表示（input）

```main.js 
const text = document.querySelector('textarea');

text.addEventListener('input', () => {
  console.log(text.value.length);
})
```

#### 送信された時にメッセージを出力（submit）

※フォームを送信するとページ遷移が発生するためテキストが一瞬で消えてしまうので、既存の動作をキャンセルする必要がある。

例）
```main.js 
document.querySelector('form').addEventListener('submit', e => { //Eventオブジェクト"e"を渡し、
  e.preventDefault(); //既存の動作をキャンセル
  console.log('submit');
});
```

`.preventDefault()` ... 既存の動作をキャンセル
※clickイベントでも表示させることは可能だが、formタグを使っておくと、Enterキーでもフォームを送信できるというメリットがある。


#### イベントの伝播

入れ子になった要素において、イベントが順々に伝播する。

例。クリックするたびに打ち消し線が付いたり外れたりする。
Eventオブジェクトを使えばクリックした要素は"e.target"、EventListenerを追加した要素は"e.currentTarget"で取得できる。

```index.html
<ul> <!-- e.currentTarget -->
  <li>Todo</li>
  <li>Todo</li> <!-- e.target -->
  <li>Todo</li>
</ul>
```

```style.css
li.done {
  text-decoration: line-through;
}
```

```main.js
document.querySelector('ul').addEventListener('click', e => {
  if (e.target.nodeName === 'LI') {
    e.target.classList.toggle('done');
  }
});
```



# style属性・classの操作

#### style属性の操作

styleの指定をする場合は、`.style` の後に続けて書く。

```
element.style.プロパティ = 値;
```

例）取得する要素を定数にし、スタイルを指定する。
```main.js 
document.querySelector('button').addEventListener('click', () => {
  const targetNode = document.getElementById('target');

  targetNode.style.color = 'red';
  targetNode.style.backgroundColor = 'blue';
  }
);
``` 
※ハイフン（-）を含むstyleプロパティの場合は、繋げて次の単語の頭文字を大文字にする。

※CSSとの役割分担を明確にするため、見た目の指定はCSSに任せて、JavaScriptではclass属性の操作だけを書くようにする。


#### classの操作（classList）

classをつけたり外したりなどの指定をする場合は、`.classList` を使う。

```
element.classList.add('クラス名');
```

- `.classList`
    - `.add()`  ... クラス属性を追加する
    - `.remove()`  ... クラス属性を外す
    - `.toggle()`  ... クラス属性をが付いていなかったら追加する、付いていたら外す
    - `.contains()`  ... 特定のクラスが付いているかどうかtrue/falseで返す
- `.className = 'クラス名';` ... クラス属性を書き換える（もともとついているクラスは外れる）


書き方の例。buttonをクリックすると、#targetに.my-colorというclass属性がついていなかったら追加する、ついていたら外すという処理をするようにする。

```main.js 
document.querySelector('button').addEventListener('click', () => {
  const targetNode = document.getElementById('target');

  if (targetNode.classList.contains('my-color') === true) {
    targetNode.classList.remove('my-color');
  } else {
    targetNode.classList.add('my-color');
  }
});
```
上記のif文は `.toggle` を使うと下記のように短く表せる。

```main.js 
    targetNode.classList.toggle('my-color');
```



# カスタムデータ属性（data-*）

HTMLでは独自の属性を設定できるので、その値をJavaScriptで取得して操作する。
※カスタムデータ属性の名前は `data-` で始まる。

まずHTMLでカスタムデータ属性を記述。

```
<要素 data-***="値">テキスト</要素>
```
JavaScriptでカスタムデータ属性の取得。

```
const 定数名 = document.querySelector('要素名');
```
値を取得する時は、以下のように置き換える。
`data-***` → `dataset.***`
※datasetというプロパティが、その要素が持つすべてのdata属性の集まり。

```
console.log(定数名.dataset.***);
```

書き方の例。data-nameというデータ属性にTitleという値を設定。

```index.html 
<h1 id="target" data-name="Title">タイトルだよ</h1>
```
buttonをクリックすると、#targetのテキスト内容がデータ属性"data-name"の値に変わるようにする。

```main.js 
document.querySelector('button').addEventListener('click', () => {
  const targetNode = document.getElementById('target');

  targetNode.textContent = targetNode.dataset.name; //data-name -> dataset.name
});
```

# 要素をDOMに追加・削除

#### 要素をDOMに追加

JavaScriptでHTML要素を生成する時は、`.createElement()` を使う。

```
const 定数名（作成する要素名） = document.createElement('HTML要素');
```
子要素の末尾に追加する時は `.appendChild()` を使う。

```
親要素.appendChild('作成した要素名');
```

書き方の例。buttonをクリックすると、ulの子要素の末尾にli要素の"items 2"が追加されるようにする。

```main.js 
document.querySelector('button').addEventListener('click', () => {
  const item2 = document.createElement('li'); //li要素を作る
  item2.textContent = 'item 2'; //中身のテキストを設定する

  const ul = document.querySelector('ul'); //親要素を取得
  ul.appendChild(item2); //親要素に対して子要素の末尾に追加
});
```

#### 要素を複製してDOMに追加

要素を複製する時は `.cloneNode` を使う。

```
const 定数名（複製して作られる要素名） = element.cloneNode(true);
```
1つ前に追加する時は `.insertBefore()` を使う。

```
親要素.insertBefore(追加する要素, 追加する後ろの要素);
```
書き方の例。

```main.js 
document.querySelector('button').addEventListener('click', () => {
  const item0 = document.querySelectorAll('li')[0]; //HTML要素の1つめのli要素にitem0と名前をつける
  const copy = item0.cloneNode(true); //item0を複製

  const ul = document.querySelector('ul'); //親要素を取得
  const item2 = document.querySelectorAll('li')[2];//1つ前の要素を取得
  ul.insertBefore(copy, item2); //copyをitem2の前に追加
});
```

#### DOMから要素を削除

```
削除する要素.remove();
```
ただし上記はIEだと効かず、IE対応するなら以下を使う。

```
親要素.removeChild('削除する要素');
```


# フォームから値を取得

#### テキストボックスから値を取得

inputで入力された値は `.value` で取得できる。

```
const 定数名 = document.getElementById("定数名").value;
```

書き方の例。テキストボックスで入力を受け取り、list要素を作成する。

```main.js 
document.querySelector('button').addEventListener('click', () => {
  const li = document.createElement('li'); //リストに追加するli要素（定数名：li）を作成
  const text = document.querySelector('input'); //input要素を取得
  li.textContent = text.value; //inputで入力された値を取得
  document.querySelector('ul').appendChild(li); //親要素に対して子要素の末尾にliを追加 ※liは定数名なので""で囲わない
});
```

#### セレクトボックスから値を取得

- 選択された値は `.value` で取得。（タグの中身が使われるが、別の値にしたい場合はHTMLでvalue属性を指定）
- `.selectedIndex` はindex番号を表す。

書き方の例。セレクトボックスで選択された値を受け取り、list要素を作成する。

```main.js  
document.querySelector('button').addEventListener('click', () => {
  const li = document.createElement('li'); //li要素を作成
  const color = document.querySelector('select'); //select要素を取得してcolorという定数名をつける
  li.textContent = `${color.value} - ${color.selectedIndex}`; //valueプロパティ、selectedIndexプロパティのそれぞれで選択された値を表示
  document.querySelector('ul').appendChild(li); //親要素を取得して子要素の末尾にliを追加
});
```


#### ラジオボタンから値を取得

書き方の例。ラジオボタンで選択された値を受け取り、list要素を作成する。

```main.js
document.querySelector('button').addEventListener('click', () => {
  const colors = document.querySelectorAll('input'); //すべてのinput要素を取得
  let selectedColor; //選択された値を保持するため、変数を宣言

  colors.forEach(color => {
    if (color.checked === true) {
      selectedColor = color.value;
    } //要素がチェックされていたら、その値をselectedColorに代入
  });

  const li = document.createElement('li'); //リストに追加するli要素（定数名：li）を作成
  li.textContent = selectedColor; //liに選択された値を入力
  document.querySelector('ul').appendChild(li); //親要素を取得して子要素の末尾にliを追加
});
```

#### チェックボックスから値を取得

チェックボックスで入力された値は `.checked` で取得できる。

書き方の例。チェックボックスで選択された値を受け取り、list要素を作成する。
チェックボックスは複数選択可なので、選択された値を配列で保持する。

```main.js
document.querySelector('button').addEventListener('click', () => {
  const colors = document.querySelectorAll('input'); //すべてのinput要素を習得
  const selectedColors = []; //選択された値を配列で保持

  colors.forEach(color => {
    if (color.checked === true) {
      selectedColors.push(color.value); //push() ... 配列の先頭に要素を追加                
    }//チェックされていたら、チェックされている要素の値を配列selectedColorsに追加
  });

  const li = document.createElement('li'); //リストに追加するli要素（定数名：li）を作成
  li.textContent = selectedColors; //※デフォルトでカンマ区切りになるので、".join(',')"は省略可能 
  document.querySelector('ul').appendChild(li); //親要素を取得して子要素の末尾にliを追加
});
```



#### 参考にさせてもらったサイトなど
- [ドットインストール/詳解JavaScript 基礎文法編](https://dotinstall.com/lessons/basic_javascript_grammer_v2)
- [ドットインストール/詳解JavaScript オブジェクト編](https://dotinstall.com/lessons/basic_javascript_objects_v2)
-  [MDN/JavaScript オブジェクトの基本](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics)
- [JavaScriptのオブジェクトと、DOMを理解しよう](https://knowledge.cpi.ad.jp/other/220/)
- [ドットインストール/詳解JavaScript DOM編](https://dotinstall.com/lessons/basic_javascript_dom_v2)
- [JavaScript data-属性の操作](https://chaika.hatenablog.com/entry/2019/06/08/090000)
- [バブリングによるイベントの伝播](https://www.codegrid.net/articles/addEventListener-1/#toc-5)



# 最後に

Javascriptは、3年くらい前にProgateでさらっと勉強したくらいで、苦手意識を持ち続けながらなんとな〜く使っていたんですが、この機にガッツリ勉強してある程度読み解けるようになりたいと思います。