【備忘録】関数【TypeScript】

# 関数

TypeScript,JavaScript 初学者が**関数**について勉強したのでメモを残す。

## JavaScript の関数

JavaScript において関数は**式**もしくは**文**で定義できる。

- **式（Expression）**
  - **評価した結果を変数に代入できるもの**。
  - 変数、関数呼び出し、リテラル、式と演算子の組み合わせも全部**式**。
  - 式を評価すると結果の値を得ることができる。（**評価値**）
- **文（Statement）**
  - `if文`や`for文`は文。
  - なんらかの手続きを処理系に命令するもの。
  - 文の末尾にセミコロンを置くことで文を区切る。

## if 文と三項演算子（条件演算子）

if 文は文なので変数に代入できないが、同じように条件を扱う三項演算子は変数に代入できる。

```typescript
//  if文は文のため変数に代入はできない
const judge = if(isEven) 'even' else 'odd'; // NG
//  三項演算子（条件演算子）は式のため変数に代入可
const judge = isEven ? 'even' | 'odd';  // OK
```

## 関数宣言文と関数式

### 関数宣言文の定義

```typescript
function double(n) {
  return n * 2;
}
```

### 関数式の定義

```typescript
const twice = function (n) {
  return n * 2;
};
```

_※JavaScript では`{}`のブロックで終わる場合はセミコロン`;`をつけない例外規則が存在する。関数式では関数を変数に代入しているためセミコロンが必要。_

- 宣言文は再代入ができてしまうため、基本的には`const`で再代入不可の関数式を宣言して使うことが安全。

# 第 1 級オブジェクト（First-Class Object）

```typescript
> const func = function () {};
undefined
> func.__proto__.constructor.name
'Function'
> func.__proto__.__proto__.constructor.name
'Object'
```

- 上記のように、JavaScript では関数はビルドインオブジェクト`Function`のインスタンスであり、第一級オブジェクトでもある。
- 第一級オブジェクトには、以下の特徴がある。
  - 変数に代入可
  - 配列の要素やオブジェクトのプロパティ値にできる
  - 関数に引数として渡せる
- 関数を第一級オブジェクトとして扱うことができる言語の性質を「**第一級関数**」という。
- 関数式は`Function`オブジェクトを生成するリテラルである。

  ```typescript
  // Functionオブジェクトでインスタンス生成
  const sum = new Function('n','m','return n + m');

  // ↓この定義と↑この定義はほぼ等価
  // 関数式で定義
  const add = functoin (n,m) {
      return n + m;
  }
  ```

  _※Function オブジェクトでインスタンス生成する場合、グローバルスコープで実行されるため推奨されない。_

- オブジェクトのプロパティとして関数（メソッド）を持たせることもできる

  ```typescript
  const dog = {
      name: 'pochi',
      bark: function() = {
          console.log('bow!');
      },
      //  こうとも書けるよ↓
      //  bark(){
      //    console.log('bow!');
      //  }
  }

  dog.bark(); // bow!
  ```

# アロー関数と無名関数

## アロー関数の定義

```typescript
const plusOne = (n) => {
  return n + 1;
};
// この書き方でも可↓
// const plusOne = n => n + 1;
```

メソッドでない関数に適しており、コンストラクタとして使うことはできない

### なぜアロー関数なのか

- 関数を短く描きたい

  - 関数なのに、いちいち`function`を書かなくて良い
  - 引数が 1 つしかない場合、引数の括弧を省略できる
  - 関数の文（Statement）が`return`のみの場合、`return`も括弧も波括弧も省略できる
  - オブジェクトから直接プロパティを取得できる

    ```typescript
    const arrays = [
      [1, 2, 3],
      [4, 5, 6],
      [7, 8, 9],
    ];

    arrays.map(({ length }) => length); // [ 3, 3, 3 ]
    ```

- `this`を束縛したくない（追記予定）

## 無名関数（匿名関数）の定義

```typescript
> // 宣言文で定義しても
> function sampleFunction() {}
> sampleFunction.name
'sampleFunction'
>
> // 関数式で定義しても
> const function sampleFunc() {}
> smapleFunc.name
'sampleFunc'
```

関数には名前がついている（`Function`インスタンスの name プロパティに関数の名前が入る）

```typescript
> (function(){}).name
''
> (()=>{}).name
''
```

名前をつけなくても関数を定義することはできる。（無名関数）

### なぜ無名関数なのか

- 名前がないため、変数に代入しない限り定義した側から消える。
- 名前を考える手間が省ける。

ここで一度、アロー関数（関数式）を思い出す。

```typescript
// 関数式の定義
const twice = function (n) {
  return n * 2;
};
// アロー関数による関数式の定義
const twice = (n) => {
  return n * 2;
};
```

- 関数式での関数の定義とは、無名関数を変数（例の twice）に代入することでメモリに残すというもの

### ついでに即時関数

```typescript
// 即時関数の定義
const twice = (function (n) {
  return n * 2;
})(2);

console.log(twice); // 4
```

#### なぜ即時関数なのか

- グローバルスコープと関数スコープを使い分けることができる
- 再利用されない関数の処理、関数スコープ外に影響を及ばさないために使用できる

# 参考

- [文と式 - JavaScript Primer](https://jsprimer.net/basic/statement-expression/)
- [りあクト！ TypeScript で始めるつらくない React 開発 第 3 版【Ⅰ. 言語・環境編】](https://booth.pm/ja/items/2368045)
- [【JavaScript 入門】すぐわかる！無名関数とは - 侍エンジニア塾](https://www.sejuku.net/blog/60321)
- [アロー関数 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
- [【JavaScript】アロー関数式を学ぶついでに this も復習する話](https://qiita.com/mejileben/items/69e5facdb60781927929)


_何か指摘等ございましたら、コメントでお願いいたします。_