[Day9] 関数の高度な機能 part1

本記事は一人アドベントカレンダー企画の一つです。
[30代未経験エンジニアが25日後にJavaScriptをマスターするカレンダー](https://qiita.com/advent-calendar/2022)

[JAVASCRIPT.INFO](https://ja.javascript.info/)を元にJavaScriptを勉強していき、そこで学んだ知識をアウトプットしていきます。
２５日でJAVASCRIPT.INFOをやりきり、未経験エンジニアがJavaScriptをマスターする過程を投稿していきます。



## 6.1 再帰とスタック
### 知らない単語
- 再帰とは
    - 何回も同じ関数を呼び出す事、自分で自分自身を呼び出す

### 学んだこと
- 2つの考え方

下記は通常のループである

```javascript
function pow(a,b){
    let result = 1;
    for(i = 1; i <= b; i++){
        result *= a;
    }
    return result;
```


下記が再帰の書き方である
pow(2, 3)の場合
```javascript
function pow(a, b) {
  if (b == 1) {
    return a;
  } else {
    return a * pow(a, b - 1);
  }
}

alert( pow(2, 3) ); // 8
```
結果は8が出力される
この再帰の書き方がこの章で 1番重要である

- 実行コンテキストとスタック

実行コンテキスト(execution context) は関数の実行に関する詳細を含む内部のデータ構造で、状態管理をしている

### 感想
再帰はシンプルに記述せき、データ構造を扱う場合にも役立つので的確に使えるようにしたい。


## 6.2 残りのパラメータ(Rest parameters)とスプレッド演算子(Spread operator)
### 知らない単語
- argumentsとは
    - 引数の事

### 学んだこと
- 残りのパラメータ ‘…’

関数は、任意の数の引数で呼ぶことができる
```javascript
function sum(x, y) {
  return x + y;
}

alert( sum(1, 2, 3, 4, 5) );
```
このようなコードがあったとすると、最初の2つだけが使われる事になる
引数と数が合っていないが、指定されていないものは無視される

しかし、「…変数名」を使用すると全ての引数が格納される
例えば
```javascript
function sumAll(...args) { // args は配列の名前
  let sum = 0;

  for (let arg of args) sum += arg;

  return sum;
}
alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6
```
このようにsumAll()内は任意の数の引数で呼ぶ事ができている

- 残りのパラメータは最後である必要がある
```javascript
function f(arg1, ...rest, arg2) { // arg2 after ...rest ?!
  // error
}
```
残りのパラメータはすべての残っている引数をまとめるので、上記なら「...rest」は最後に書かないといけないので注意する

- arguments変数

argumentsは配列ではないので、map()などのメソッドは使えない
さらにアロー関数はargumentsを持たない

- スプレッド演算子
例えば下記のようにMath.max()に「arr」を入れるとエラーになる
```javascript
let arr = [3, 5, 1];

alert( Math.max(arr) ); // NaN
```
しかし「...arr」にかえる事で正しく動作する
```javascript
let arr = [3, 5, 1];

alert( Math.max(...arr) ); // 5 (配列を引数のリストに変換する)
```

つまり、配列やオブジェクトのコピーはスプレッド演算子を使用するとよい

### 感想
残りのパラメータやスプレッド演算子を使用する事でシンプルに書く事ができると思うので、上手に使用していきたい。


## 6.3 変数スコープ、クロージャ
### 知らない単語
- スコープとは
    - プロジェクトの成果物または機能の詳細なセットの事

- クロージャ
    - あるコードブロック内で定義された関数などが、そのブロックをスコープとする変数などを参照できる事

### 学んだこと

- コードブロック

ここで説明されている事は、スコープとは中カッコ{}での領域の事で、別の中カッコから変数などを呼び出す事はできない

例
```javascript
{
  // 外には見せる必要のない、ローカル変数で処理をする

  let message = "world"; // このコードブロックでだけ見える

  alert(message); // world
}
alert(message); // Error: message is not defined
```
このように中カッコの外では、この変数が定義されていないので、エラーになる

- ネストされた関数

別の関数の内部で作成される関数は、“ネストされた” 関数と呼ばれる
```javascript
function sayHiBye(firstName, lastName) {

  // 下で使うネストされたヘルパー関数です
  function getFullName() {
    return firstName + " " + lastName;
  }

  alert( "Hello, " + getFullName() );
  alert( "Bye, " + getFullName() );

}
```
ここでネストされた 関数 getFullName() は利便性のために作られているが、それは外部変数にアクセスすることができるので、フルネームを返せる
しかし、このコードの外では定義されていないので使えない、あくまで中カッコ内のみ


### 感想
中カッコの外では、その中で定義された変数でなければエラーになるので、カッコ内だけで使うのかグローバル変数にするのかをちゃんと決めておく。


## 6.4 古い "var"
### 知らない単語
- エミュレートとは
    - 本来のハードウェアやソフトウェアと同じ機能を、別のハードウェアやソフトウェアが真似る事

### 学んだこと

- 変数を宣言する3つの方法

let
const
var

var 宣言は let と同じような振る舞いをする
しかし、内部的には var は昔から使われてきた、全く異なるものである

- varは再宣言を許容します

ここで重要な事はvarは2回同じ変数を定義できる事である

let で同じ変数を宣言すると、エラーになる
```javascript
let user;
let user; // SyntaxError: 'user' has already been declared
```

しかし、varでは何度も同じ変数の定義ができる
```javascript
var user = "Bill";

var user = "John"; // ...エラーは発生しない

alert(user); // John
```

このようにvarは同じ変数を何度も定義できるが、不具合になるので現在は使われていない

### 感想
自分自身はvarでコードを書いた事は無いので使わないが、varが古い書き方だという事を覚えておきたい。


## 6.5 グローバルオブジェクト
### 知らない単語
- 無し

### 学んだこと
グローバルオブジェクトはどこでも利用可能な変数と関数を提供する

- windowオブジェクトは共通なので省略できる
例えば
```javascript
alert("Hello");
// 同じ
window.alert("Hello");
```
このようにどちらを使っても同じである


- polyfill のための使用
グローバルオブジェクトを使って、最近の言語機能のサポートをテストする
例えば、組み込みの Promise オブジェクトが存在するか？
```javascript
if (!window.Promise) {
  alert("Your browser is really old!");
}
```
要するにwindow.Promiseなど新しいものは古いバージョンでは動かない

### 感想
省略できる所は省略して、新しい書き方を取り入れてバージョンアップする事が重要であると思った。


# 最後に
この章で解説されていた事は難しい事はあまり無いが、書き方や処理のルールをしっかり覚えておくべきだと思った。