JavaScript基礎文法入門を焼肉で(2)

#この記事について
JavaScript基礎文法入門の、学習内容のアウトプット・自身の振り返り用のメモ2です。
メモ1：[JavaScript基礎文法入門を焼肉で(1)](https://qiita.com/yojij_yojij/items/3bf87faecd0ff647a453)

**参考資料**
[Progate JavaScript(ES6)学習コース](https://prog-8.com/languages/es6)
[ドットインストール 詳解JavaScript 基礎文法編](https://dotinstall.com/lessons/basic_javascript_grammer_v2)

# 【クラス】
Webサービスなどでは、オブジェクトをいくつも扱っている
毎回ゼロから作成していては大変なので、似たようなデータを効率よく作成する必要がある

そのための方法として、最初に「設計図」を用意する方法がある
例えばユーザー（利用者）のデータ（オブジェクト）をいくつも作成する場合、最初に「ユーザーを生成するための設計図」を用紙し、その設計図を基にユーザーのデータを生成していく、といったことができる。

この設計図のことをJavaScriptでは「クラス」と呼ぶ
クラス名は基本的に「大文字」から始める

```
class Meat {
}
```

#### インスタンスの生成
クラスからオブジェクトを生成するには「new クラス名( )」とする
クラスから生成したオブジェクトは「インスタンス」と呼ぶ

```
class Meat {
}
const meat = new Meat(); //Meatインスタンス
console.log(meat);
```

#### コンストラクタの処理
コンストラクタの中には処理を記述できる
この処理は、インスタンスが生成された直後に実行され、
インスタンスごとに毎回実行される

```
class Meat {
    constructor () {
      console.log("美味しい！");
    }
}
const meat1 = new Meat();
const meat2 = new Meat();
```

「this.プロパティ = 値」とすることで
生成されたインスタンスにプロパティと値を追加できる
インスタンスとはオブジェクトなので、コンストラクタの中で追加した値は
「インスタンス. プロパティ」とすることでクラスの外で使用できる

```
class Meat {
  constructor() {
    this.name = "hatsu"; //プロパティと値
  }
}
const meat = new Meat();
console.log(meat.name); //コンストラクタで設定した値が使える
```

コンストラクタでは引数を受け取ることが可能
constructorの後の( )に引数を記述することで
その引数をコンストラクタの処理内で使用できる

```
class Meat {
  constructor(name, price) { //引数を受け取る
    this.name = name;
    this.price = price;
  }
}
const meat = new Meat("hatsu", 900);
//文字列"hatsu"という値が引数として渡され、コンストラクタ内ではnameとして使える
```

#【メソッド】
メソッドは、そのクラスから生成したインスタンスに対して呼び出す
「インスタンス. メソッド名( )」とすることでそのメソッドを呼び出し処理を実行できる

```
class Meat {
  constructor(name, price) {
    |
  }
  greet() {　　　　　　　　　　　//メソッド名
    console.log("実質タダ！");  //処理
  }
}
const meat = new Meat("hatsu", 900);
meat.greet(); //メソッドの呼び出し
```
メソッド内でインスタンスの値を使用するには「this.プロパティ名」とする

```
class Meat {
  |
  info() {
    consolo.log(`名前は${this.name}です`);
　　　//インスタンスのnameプロパティの値になる
  }
}
const meat = new Meat("hatsu", 900);
meat.info();

```

メソッド内で他のメソッドをを呼び出すことも可能
メソッド内で「this.メソッド名( )」とすることで同じクラスの他メソッドを使用できる

```
class Meat {
  greet() {
    console.log("実質タダ！");
  }
  info() {
    this.greet(); //同じクラスのメソッドを実行
      |
  }
}
```

#【継承】
既にあるクラスを基に、新しくクラスを作成する方法
継承を用いてクラスを作成するには「extends」を用いる

```
class Beef extends Meat { //Meatクラスを継承
}
//基となるクラスを親クラス、新しく作成するクラスを子クラスと呼ぶ
```
子クラスは親クラスのすべての機能を引き継いでいる
そのため、子クラス内には何もメソッドが定義されていなくても
親クラスに定義されているメドッドは使用できる

```
class Meat {
  constructor(name,price) {
    this.name = name;
    this.price = price;
  }

  greet() {
    console.log("いらっしゃいませ!");
  }

  info() {
    this.greet();
    console.log(`${this.name}ですね`);
    console.log(`${this.price}円です`);
  }
}
class Beef extends Meat {
}
const beef = new Beef("和牛タン", 3000);
beef.info(); //Meatクラスに定義されているメソッドを使用できる
```

#### 継承したクラスでの独自メソッド
継承したクラスにもメソッドを追加できる
関数と同じように戻り値を用いることもできる

```

class Beef extends Meat {
  many() {
    return this.price *2; //メソッドでも戻り値は使える
  }
}

const beef = new Beef("和牛タン", 3000); //このメソッドの戻り値が代入される
const many = beef.many();
console.log(many);
```

子クラスの定義した独自メソッドは、親クラスクラスから呼び出すことはできない

```
class Beef extends Meat {
  many() {
    return this.price *2;
  }
}

const meat = new Meat("和牛タン", 3000);
const many = meat.many(); //manyメソッドはBeefクラスにしかないのでエラー
```

#### オーバーライド
親クラスと同じ名前のメソッドを子クラスに定義すると上書きされ、子クラスのメソッドが優先して使用される

```
const beef = new Beef("和牛タン", 3000);
beef.info ():
class Meat {
  info() {
    |
  }
}
class Beef extends Meat {
  info() { //子クラスのinfoメソッドが呼び出される
    |
  }
}
```

#### コンストラクタのオーバーライド
メソッドと同じように、コンストラクタもオーバーライドすることができる
例えば、子クラスにプロパティを追加したい場合などに用いる
ただし、コンストラクタをオーバーライドするする際は、1行目に「super( )」と記述する

```
class 親クラス　{
  constructor() {
    |
  }
}
class 子クラス extends 親クラス　{
  constructor {
    super() //一行目に super()が必要
    //子クラスのコンストラクタの処理
  }
}
```

子クラスのコンストラクタ内の「super( )」では、
その部分で親クラスのコンストラクタを呼び出している
そのため、親クラスのコンストラクタが引数を受け取る場合には
「super」の後ろの「( )」に引数を渡す必要がある

```
class Meat {
  constructor(name, age) { //1.親クラスのコンストラクタ実行
    this.name = name;
    this.price = price;
  }
    |
}
class Beef extends Meat {
  constructor(name, price, many) {
    super(name, age);
    this.many = many; //2.子クラス独自の処理実行
  }
    |
}
```

#【複数ファイルの扱い方】

#### ファイルの分割
コードの量が増えてくると1つのファイルで管理するのが大変になるため
複数のファイルでコードを管理することがある

#### ファイル分割時のエラー
ファイルを分割したことで、ファイル内に必要な値がなくなるとエラーとなる

#### export
クラスの定義の後で「export default クラス名」とすることで、
そのクラスをエクスポート（出力）し、他のファイルへ渡すことができる

```
class Meat {
  |
}
export default Meat; //Meatクラスを他のファイルでも使用できるようにする設定
```

#### import
他のファイルで定義されているクラスを使用するにはインポート（読込）をする必要がある
使用するファイルの先頭で「import クラス名 from ". / ファイル名"」と書くことでインポートできる
ファイル名の拡張子の「.js」は省略可

```
import Meat from "./meat"; //Meatがクラス名、"./meat"がファイル名
```

#### 値のエクスポート
文字列や数値や関数など、どんな値でもエクスポートが可能
エクスポートする際は、「export default 定数名」とする
インポートする際は、「import 定数名 from "./ファイル名"」とする

```
＜sample1.js＞
const text = "Hello Yakiniku";
export default text;
```

```
＜sample2.js＞
import text from "./sample1";
HTMLFormControlsCollection.log(text)
```

#### デフォルトエクスポート
export defaultはデフォルトエクスポートを呼ばれ、そのファイルがインポートされると
自動的に「export default 値」の値がインポートされる
そのため「エクスポート時の値の名前と、インポート時の値の名前に違いがあっても問題ない」

```
＜sample1.js＞
const meat = new Meat("和牛ホルモン", 1200, 2);
export default meat; //meatがエクスポート
```

```
＜sample2.js＞
import oniku from "./sample1"; //名前が違うが定数meatの値が入る
oniku.info();
```

#### 名前付きエクスポート
デフォルトエクスポートは値を自動でインポートするため1ファイル1つの値のみ
複数の値をエクスポートしたい場合は、「名前付きエクスポート」を用いる

defaultを書かずに、名前を{ }で囲んでエクスポートする書き方
インポートする値は、エクスポート時と同様に
「import {値の名前} from "./ファイル名"」と{ }で囲んで指定する

また「export {名前1, 名前2}」という形で書くことにより
1つのファイルから複数のエクスポートができる
インポートの際も、コンマで区切ることで複数のインポートができる

```
＜sample1.js＞
const meat1 = new Meat("イチボ", 1200, "牛");
const meat2 = new Meat("ぼんじり", 800, "鶏");
export {meat1, meat2};
```

```
＜sample2.js＞
import {meat1, meat2} from "./sample1";
meat1.info();
meat2.info();
```

#【配列を操作するメソッド】

#### pushメソッド
配列の最後に新しい要素を追加するメソッド
pushメソッドの後の( )の中に追加したい要素を入力する

```
const meats = ["レバー", "ハツ", "ミノ"];
console.log(meats);
meats.push(シマチョウ); //配列に新しい要素を追加する
console.log(meats);
```

#### forEachメソッド
配列の中の要素を1つずつ取り出して、全ての要素に繰り返し同じ処理を行うメソッド

```
const meats = ["レバー", "ハツ", "ミノ"];
meats.forEach((meats) => {
 console.log(meats);
});
```

forEachメソッドの引数には「アロー関数」が入っている
配列内の要素が1つずつ順番にアロー関数の引数に代入され、処理が繰り返し実行される

```
配列 = [要素1, 要素2, 要素3]; //要素1〜3が引数へ
配列.forEach((引数) => {処理}); //(引数) => [処理} の部分がアロー関数
配列の中の要素を1つずつ取り出して同じ処理をする
```

#### findメソッド
コールバック関数の処理部分に記述した、
条件式に合う1つ目の要素を配列の中から取り出すメソッド
配列meatsの要素が1つずつ引数meatに代入されて処理が進む
コールバック関数の中は { return 条件 } と書くことで、条件に合う要素が戻り値となる
findメソッドは条件に合う要素が見つかった時に終了するので、条件に合う最初の1つの要素しか取り出せない

```
const meats = ["レバー", "ハツ", "ミノ"];
const foundMeat = meats.find((meat) => {
  return meat === "ミノ";
});
console.log(foundMeat);
```

配列の要素がオブジェクトの場合もfindメソッドを使うことができる
以下の例ではオブジェクトのプロパティを条件の中で使用している
オブジェクトのプロパティを条件として使用する場合、そのプロパティを持っているオブジェクトそのものを取り出しす

```
＜script.js＞
const meats = [
  {id: 1, name: "ヒレ", price: 2000},
  {id: 2, name: "ミスジ", price: 1500}
];
const foundMeat = meats.find((meat) => {
return meat.id === 1;
});
console.log(foundMeat);
```

#### filterメソッド
記述した条件に合う要素のみを取り出して新しい配列を作成するメソッド
下記の例では配列numbersの要素が1つずつ引数numberに代入される
その後、filterメソッド内で「3より大きい数字」かどうかを判定し、
条件に合う要素が定数filteredNumbersに配列として代入される

```
const numbers = [1, 3, 5, 7];
const filteredNumbers = numbers.filter((number) => {
  return number > 3;
});
console.log(filteredNumbers);
// 条件に合う要素がすべて取り出されて新しい配列の中に入る
```

findメソッドと同様に、配列の要素がオブジェクトの場合もfilterメソッドを使うことができる
下記の例ではオブジェクトのプロパティを条件の中で使用している
オブジェクトのプロパティを条件として使用する場合、そのプロパティを持っているオブジェクトそのものを取り出す

```
const meats = [
  {name:"レバー", price: 750},
  {name:"ハツ", price: 850},
  {name:"ミノ", price: 800}
];
const filteredMeats = meats.filter((meat) => {
  return meat.price <= 800 ;
});
  console.log(filteredMeats);
```

#### mapメソッド
配列内のすべての要素に処理を行い、その戻り値から新しい配列を作成するメソッド
下記の例では配列numbersの全ての要素を2倍した要素を持つ、新しい配列を作成している
コールバック関数の中の処理は { return 値 } と書く

```
const numbers = [1, 2, 3];
const doubledNumbers = numbers.map((number) => {
  return number  * 2;
});
console.log(doubledNumbers);
// 全ての数字が2倍された新しい配列が作成され定数doubledNumbersに代入
```

mapメソッドも配列のオブジェクト要素に対しても使うことができる
以下の例では、mapでfirstNameプロパティとlastNameプロパティを繋げる処理をしている

```
const names = [
  {firstName: "焼肉", lastName: "吾郎"},
  {firstName: "お肉", lastName: "太郎"}
];
const fullNames = names.map((name) => {
  return name.firstName + name.lastName;
});
console.log(fullNames);
```

#【コールバック関数】
ある他の関数に引数として渡される関数を「コールバック関数」と呼ぶ

```
umbers.forEach((number) => {console.log(number);});
　　　　　　　　　----------------------------------
                      　コールバック関数
```

#### 引数の種類
JavaScriptでは引数に関数を渡すことができる
引数に渡される関数をコールバック関数と呼ぶ

```
関数呼び出し時に渡される引数の種類
文字列
数値
真偽値
関数　//引数に渡される関数をコールバック関数という
```

#### 関数の呼び出し方・渡し方

関数名の後ろに( )をつけると呼び出され、( )をつけなければ関数そのものを指す
呼び出し方と渡し方で書き方が異なる

関数の扱い方
kurogeWagyu( )・・・関数が呼び出される
kurogeWagyu・・・関数の定義そのもの

```
const kurogeWagyu = () => {
  ｜
};
const call = (callback) => {　・・・関数kurogeWagyuが代入される
  |
};
call(kurogeWagyu);　・・・関数kurogeWagyuを引数に渡す
```

関数を直接引数の中で定義することもできる

```
const kurogeWagyu = () => {
  console.log("サーロイン");
};

const call = (callback) => { //2.関数をcallbackに代入
  console.log("コールバック関数を呼び出す");
  callback(); //3.関数callbackを呼び出す
};

call(kurogeWagyu);

call(() => { //1.引数で関数を定義して関数callを呼びだす
  console.log("シャトーブリアン");
});
```

コールバック関数では、普通の関数と同じように引数を複数渡すことができる

```
＜普通の関数の場合＞
const introduce = (name, price) => {
  console.log(`${name}は"{price}円です。`);
};
introduce("シャトーブリアン", 15000);
```

```
＜コールバック関数の場合＞
const introduce = (callback) => {
  callback("シャトーブリアン", 15000);
};
introduce((name, price) => {
  console.log(`${name}は${price}円です。`);
});
// コールバック関数の引数と、実行時に渡す引数の数をそろえるように気を付ける
```