JavaScript Primerを読んでみた

# はじめに
今回は JavaScript Primerを読んだのでアウトプットしていきます。
なかなかタフでした...

https://jsprimer.net/

# 良かったこと
1つの記法やメソッドについてかなり詳しく書いていたことが良かった。
国語辞典を読んでいる感覚になった。

JavaScriptを学ぶ最初の1冊にするよりかは
YoutubeやUdemyでJavaScript初心者用の動画を1つ見てから取り組んだらより理解が深まる書籍だと思う。

実際にJavaScriptの課題に取り組んでから辞書的な扱いにするのが良いと考えている。
# 学んだこと
## const
**再代入できない**変数
## let
**再代入ができる**変数を宣言
## var （※注意）
letと同じく再代入ができる変数を宣言できる

## 型検索
`typeof`演算子を使用
オブジェクトの詳細な種類を判定できない
`Object.prototype.toString`でより詳細な型チェックができる

## `==`を使う時
`null` と `undefined`の比較

## 文字列を数値に変換
`Number`コンストラクタ関数を利用する

## `NaN`というもの
`NaN`は Not a Numberの略称で、特殊な性質を持つNumber型のデータ
`NaN`は暗黙的な型変換の中で最も避けたい値
理由は何と計算しても結果は `NaN` になる

`NaN`しか持っていない特殊な性質として、自分自身と一致しない

## arguments
可変長引数を扱う方法として、関数の中でのみ参照できる特殊な変数
可変長引数が必要な場合は `arguments` 変数よりも、`Rest parameters` での実装

## `for...in`文の問題点
オブジェクトのプロパティに対して、反復処理をする場合は
`for`文, `forEach`, `for..of`, `Object.keys` を利用する

## オブジェクトの省略記法
プロパティと値が同じ名前の場合は以下のように省略可能
```js
const baseball = "野球";
// `baseball`というプロパティ名で`baseball`の変数を値に設定したオブジェクト
const obj = {
    baseball  // baseball: baseballと同じ意味
};
console.log(obj); // => { baseball: "野球" }
```

## オブジェクトと分割代入

```javascript
const ja = languages.ja;
const en = languages.en;
console.log(ja); // => "日本語"
console.log(en); // => "英語"
```

```javascript
// ↓以下のように1行でかける↓
const { ja, en } = languages;
console.log(ja); // => "日本語"
console.log(en); // => "英語"
```

## プロパティの存在を確認する方法
-  in演算子
```javascript
const obj = { key: undefined };
// `key`プロパティを持っているならtrue
if ("key" in obj) {
    console.log("`key`プロパティは存在する");
}
```
- Object.hasOwn静的メソッド
```javascript
const obj = { key: undefined };
// `obj`が`key`プロパティを持っているならtrueとなる
if (Object.hasOwn(obj, "key")) {
    console.log("`obj`は`key`プロパティを持っている");
}
```

## 作成したオブジェクトのプロパティの変更を防止
- `Object.freeze`静的メソッドを利用
:::note warn
`Object.freeze` 静的メソッドを利用する場合は必ずstrict modeと合わせて使用
`strict mode` ではない場合は、凍結されたオブジェクトのプロパティを変更しても例外が発生せずに単純に無視される
:::
```js
"use strict";
const countries = Object.freeze({ ja: "日本" });
// freezeしたオブジェクトにプロパティを追加や変更できない
object.ja = "フランス"; // => TypeError: "ja" is read-only
```

## Optional chaining演算子（?.）
```javascript
const obj = {
    a: {
        b: "objのaプロパティのbプロパティ"
    }
};
// obj.a.b は存在するので、その評価結果を返す
console.log(obj?.a?.b); // => "objのaプロパティのbプロパティ"
console.log(obj?.b?.a); // => undefined
```

## オブジェクトのマージ（合体）
`Object.assign`静的メソッドを使用することで可能
第一引数には、空のオブジェクトリテラルを指定するのが典型的な利用方法
プロパティ名が重複した場合は、後ろのオブジェクトのプロパティにより上書きされる

## プロトタイプオブジェクト

空のオブジェクトであってもメソッドが使用できるのは、プロトタイプオブジェクトがあるから。


```js
const obj = {};  // 空のオブジェクト以下の toString メソッドを定義してない
console.log(obj.toString());
```
この `toString` が使える理由は以下
- オブジェクト(今回の例では作成した`obj`)の継承元の `Object` (`prototype` オブジェクト)で定義されているから
- その結果、オブジェクトを作成した時点で `Object` を継承している

もし、プロトタイプオブジェクトと同じ名前のインスタンスメソッドがある場合はインスタンスメソッドの内容が優先される。

```js
const i1 = {
  name: "i1"
}

const i2 = {
  name: "i2",
  // プロトタイプメソッドと同名のメソッドをオブジェクトで定義(インスタンスメソッド)
  toString: () => {
    return "こちらが優先";
  }
}

console.log(instance1.toString());   // [object Object]
console.log(instance2.toString());   // こちらが優先(※インスタンスメソッドが優先されている)
```

## 配列操作における破壊的な操作と非破壊的な操作
結論、以下の違いがある。

破壊的な操作：**元の配列を変更する**
非破壊的な操作：**元の配列を変更せずコピーをして、コピーした配列に変更を加える**

例；配列に1つ要素を加えたい場合
```js
const nums = [1, 2, 3, 4, 5]

// 破壊的な操作の場合
nums.push(6);
console.log(nums)  // [1, 2, 3, 4, 5, 6]


// 非破壊的な操作の場合
const newNums = [...numbers, 6];
console.log(nums);  // [1, 2, 3, 4, 5]
console.log(newNums);  // [1, 2, 3, 4, 5, 6]
```

## Array-likeオブジェクト
配列っぽいけど、配列では無いもの。`length`プロパティを持つ。
`map`や`filter`などの配列メソッドを直接呼び出すことが不可能

`Array.prototype.<メソッド>`とすることで実行可能な関数もある
```js
// map
const arrayLike = {
  length: 3,
  0: 2,
  1: 3,
  2: 4,
  3: 5, // length が 3 なので map() 空は無視される
};
console.log(Array.prototype.map.call(arrayLike, (x) => x ** 2));
// [ 4, 9, 16 ]
```

`Array.from()`, スプレッド構文を使用すると
`Array-like`オブジェクトを配列に変換できる

## 正規表現のgフラグを使った繰り返しマッチ
正規表現における g フラグを使用した文字列検索で
マッチしたすべての文字列を含んだ配列が欲しい場合は
`match`メソッドより`matchAll`メソッド+ `for~of` を使用することで
より詳細な情報を取得することができる。

```js
const text = "価格は100円と200円です";
const pattern = /\d+/g;  // gフラグ → 全部見つける

// match: 結果だけほしい
const results = text.match(pattern);
console.log(results); // ["100", "200"]

// matchAll: 詳しい情報もほしい
for (const match of text.matchAll(pattern)) {
    console.log(`数字: ${match[0]}, 位置: ${match.index}`);
    // 数字: 100, 位置: 3
    // 数字: 200, 位置: 8
}
```

## クロージャー
内側の関数が外側の関数の変数にアクセスできる仕組みのこと。
外側から内側へのアクセスはエラーとなる。

```js
function createCounter() {
    let count = 0;
    return () => ++count;
}

// カウンターを作成
const counter = createCounter();
counter();
console.log(conter)  // 1
counter();
console.log(conter)  // 2
counter();
console.log(conter)  // 3
```
結果： 呼び出すたびに1ずつ増える
count変数が保持されている。

- コールバック関数とthis
対処法: Arrow Functionでコールバック関数を扱う

## Privateクラスフィールド
フィールド名の前に「#」をつけて、外部からアクセスできないようにする
機密データや計算ロジックで使用
クラス内部のメソッドでのみ操作可能である。

```js
// 例：お小遣い管理
class PocketMoney {
    #money = 0; // ← 秘密の残高（外から見えない）
    
    earn(amount) {
        this.#money += amount; // クラス内部でだけアクセス可能
    }
    
    checkMoney() {
        return this.#money; // メソッド経由でのみ確認可能
    }
}
```

## throw文
問題が発生したときに、処理を強制的に止めてエラーを投げる文。
例外処理をする際に使用。

```js
// 例：0で割るとエラーを発生させる
function divide(a, b) {
    if (b === 0) {
        throw new Error("ダメ！"); // ここで処理が止まる
    }
    return a / b; // ここは実行されない
}
```

## then や catch メソッドを使用する場面
`Promise` インスタンスの状態が変化したときに
一度だけ呼ばれるコールバック関数を登録するのが`then` や `catch` メソッドとなる。

## 非同期処理とは
簡単に言うと、〇〇しながら××すると言うことです。
ある処理を実行したあとに結果を待たずにすぐ次の処理を実行できる処理。
以下の記事でわかりやすく説明されていた。

https://qiita.com/sho_U/items/f07a4f3e7760a9729f10

https://zenn.dev/nameless_sn/articles/javascript_async_tutorial

非同期処理をすることで以下のようなことが実行できるようになります。
- 10記事のブログの読み込み→出力
    - 同期：記事1読み込み → 記事1出力 → 記事2読み込み →　記事2出力 → 記事3読み込み → 記事3出力...
    「1つ終わったらその次を読み込む」、「読み込み終わるまで次のブログを読み込めない」
    - 非同期：記事1〜10を同時に読み込み開始 → 読み込めたものから順次表示

## Promiseとは
Promise オブジェクトとは、非同期処理結果およびその結果の値を返すオブジェクト。
Promise は以下の3つの状態のいずれかになっており
一度状態が変化すると変化後の状態からは変わらない。
- 待機 (pending): 初期状態。成功でも失敗でもない
- 履行 (fulfilled): 処理が成功して完了したという意味
- 拒否 (rejected): 処理が失敗したという意味

**pending → fulfilled**
このように状態が変化する場合には、成功時の`resolved` 関数が呼び出される

**pending → rejected**
このように状態が変化する場合には、エラー時の`rejected` 関数が呼び出される

## Async Function
Promiseよりシンプルな記述で非同期処理を行う記法
純粋にthenで繋げて書くのはコードが長くなるから `async/await` が推奨される
特徴は以下
- 非同期処理を伴う関数の頭に `async` を追記
- 非同期処理を伴う関数の実行時に `await` をつける
- `await` は　`ssync` 付きの関数でしか使えない

# 難しかったこと
Promise, async/await の理解をするのに苦戦しました。
私は以下の動画で概要を掴みました。

https://youtu.be/kbKIENQKuxQ?si=5XbR9vgeOna54UaN

Promiseはかなり奥が深そうなので完璧に理解するより、都度調べて使う方が良いと感じます。


# 最後に
なかなかタフでした...。
私にとって JavaScript は第二言語となります。
これから長くお世話になっていくと思うので
JavaScriptに詰まったらお世話になろうかと考えています！