【JavaScript】=>って何？〜functionとの違い〜

# 関数
関数とは、**複数の処理をひとまとめにしたもの**です。
JavaScriptの基本的な構文の一つでもあります。

関数には**定義**と**呼び出し**があります。

- 定義: その関数でしたい処理を書く
- 呼び出し: 定義した処理を実行する
    - JavaScriptでは関数名の後に`()`をつけると呼び出せる

## 関数の定義

関数は2通りの方法で定義することができます。
- `function`キーワードを使った関数宣言
- アロー関数式（`() =>`を使った記法）

ここからは、与えられた数値`x, y`を足して返す`add`関数を例に説明します。

## 関数宣言
`function`キーワードを使った**関数宣言**では、`add`関数を以下のように書くことができます。
```js
// function 関数名(引数) { 処理 }
function add(x, y) {
  return x + y // returnで戻り値を決める
}
```

これは以下のように呼び出せます。
```js
add(1, 2) // 3が返ってくる
```

## アロー関数式
アロー関数式（`() => `を使った記法）では、`add`関数を以下のように書くことができます。

```js
// 変数の宣言 = 関数
// 関数の部分: (引数) => { 処理 }
const add = (x, y) => {
  return x + y
}
```

アロー関数を使うと、関数という種類の値を作成できます。
これは普通の値なので`const`などで宣言した通常の変数に代入できます。
これは、JavaScriptの関数が**第一級の値**だからできることです。
第一級の値とはざっくり言うと通常の値のことで、例えば数値や文字列があります。

関数が代入された変数は、通常通り呼び出すことができます。
```js
add(3, 5) // 8
```

なお、アロー関数ではブロック（`{}`）を省略し、いきなり戻り値を書くこともできます。

```js
const add = (x, y) => x + y

add(1, 3) // 4
```

## 関数式

なお、関数式と呼ばれる、`function`キーワードと変数の代入を組み合わせる方法もあります
関数式はアロー関数と同じように変数に代入したりできます。

```js
const add = function(x, y) {
  return x + y
}
```

個人的にはこのように関数式を使う機会は少なく、これが必要な場面では**アロー関数に置き換えられる**と思っています。

:::note
実は、関数式では関数に名前をつけることができます。
```js
// nameという名前をつける
const add = function name(x, y) {
  return x + y
}

add(5, 3) // OK
name(2, 3) // NG、関数につけた名前では呼び出せない
```

ややこしいですが、これは**関数宣言とは別物**です。

```js
// 関数式を変数に代入
const add = function name(x, y) {
  return x + y
}

// 関数宣言
function add(x, y) {
  return x + y
}
```

ちなみに、[式文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/Expression_statement)と呼ばれる、文を書く場所にいきなり式を書く場合があります。
これは例えば`1;`みたいな文や、関数の呼び出し（`add();`など）です。

ほとんどの式は式文として書くことができますが、関数式は式文にできません。
これは関数宣言との混同を避けるためです。
```js
// 関数式を直接書くのは構文エラー
function() {
  console.log('これはNG'); // <- ちなみにこれも関数の呼び出しなので式文
}

// 関数宣言ならOK
function test() {
  console.log('これはOK');
}

// 関数式をconstなどの文で使う（=式文じゃない）のはOK
const test = function() {
  console.log('これはNG');
};
```

リンク:
- [関数式](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/function)
- [関数宣言](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/function)
- [アロー関数式](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

@juner ありがとうございました！
:::

# 何が違うの？
では、アロー関数で定義した関数と、`function`で定義した関数は、いったい何が違いのでしょうか。

結論から言うと、**だいたい同じ**です。
そのため基本的には好みで使い分けてもいいと思います。

## 読みやすさ

これはあくまで個人の意見ですが、それぞれの記法にはこんな印象があります。
- `function`キーワード: なんだか関数感が出る
- アロー関数: 関数を関数に渡す場合主流

### 高階関数とは

関数に関数を渡すとは、高階関数の呼び出しのことです。
高階関数とは**引数に関数を取る関数**（メソッド）のことで、配列の`map`や`filter`があります。

例えば、数値を入れた配列`numbers`があるとします。
この中の値を2乗した配列を新しく作成したいです。
そんなときには、`map`メソッドが使えます。

### アロー関数の場合

下のコードでは`map`にアロー関数を渡しています。
```js
const numbers = [1, 4, 5]
const square = numbers.map(num => num ** 2)
// square: [1, 16, 25]
```

### 関数式の場合

以下のように関数式を使うこともできます。

```js
const numbers = [1, 4, 5]
const square = numbers.map(function(num) { return num ** 2 })
// square: [1, 16, 25]
```

ですが、1行で済む関数に対していちいちブロック（`{}`）や`return`を書く必要があるため、少し冗長になります。~~あと見慣れない~~

### 関数宣言の場合

`function`キーワードを使って関数宣言し、それを使うこともできます。

```js
const numbers = [1, 4, 5]

function toSquare(num) { 
  return num ** 2 
}

const square = numbers.map(toSquare)
// square: [1, 16, 25]
```

しかしその関数を一度しか使わないことが自明な場合、無駄に複数行必要になったり無駄に名前をつけることになり、少し冗長です。

何度も使いそうな場合は、こちらのほうが再利用性が高くていいかもしれません。

## this

アロー関数と`function`を使った関数では、`this`の扱いが違います。

`this`は特別な変数で、どこで参照されるかによって値が違います。
例えば、ブラウザのグローバルから参照すると`window`と同じオブジェクトが返ってきます。

オブジェクトの中で定義された関数の`this`はそのオブジェクト自身を指します。
```js
const counter = {
  count: 0,
  add: function () {
    this.count++ // thisはcounterを指す
    return this.count
  }
}
```

このコードの`this.count`は`counter`オブジェクトの`count`プロパティを指します。
そのため、`add`を呼び出すと`counter.count`がインクリメントされます。

```js
counter.add() // 1
counter.add() // 2
counter.add() // 3
```

ところが、この`function`を**アロー関数に変えた**途端、事件は起きてしまいます。
なんと、`counter.add`が`NaN`を返すようになってしまいました。

```js
const counter = {
  count: 0,
  add: () => {
    this.count++
    return this.count
  }
}

counter.add() // NaN
counter.add() // NaN
```

これはなぜでしょうか。

実は、アロー関数の中の`this`は呼び出し元に影響を受けません。
アロー関数が定義された時点の`this`に固定されます。

`function`を使った関数は、今回の呼び出し元=`counter`オブジェクトに影響を受けます。
しかしアロー関数での`this`は、**宣言した場所での`this`=`window`が使われてしまいます。**

これによって、初期化されていない`window.count`が参照され、`undefined`をインクリメントしたため`window.count`が`NaN`になってしまったようです。

:::note
個人的にはこの記法がすっきりしていてお気に入りです。
```js
const counter = {
  count: 0,
  add() { // メソッド名(引数) {処理}
    this.count++
    return this.count
  }
}
```

この記法は他より短く書けてすっきりします。
また、これは`function`で宣言するときと同じように動作するので、`this`は`counter`オブジェクトを指し、カウンターは正常に動きます。
:::

<!--
間違っていたので削除（詳細はコメント）
余裕があったらthisの固定についてとして書き直すかも

### 悪いことではない

しかし、アロー関数の`this`が変わらないのは決して悪いことではありません。

例えば、以下のように`add`メソッドに別名をつけてみます。
```js
// functionを使ってaddメソッドを定義する
const counter = {
  count: 0,
  add: function () {
    this.count++ // thisは呼び出し元によって変動する
    return this.count
  }
}

// addという名前で使えるようにする
const add = counter.add

add() // NaN
add() // NaN
```

`add`関数が**呼び出された場所での`this`は**、グローバルの`this`=`window`です。
そのためまたしても`window.count`がインクリメントされ、`NaN`が返ってきてしまいました。

これが呼び出し元によって`this`が変わる、ということです。
ややこしいですね。
しかし、アロー関数ならこのような心配はありません。

---

また、`this`を固定したいときにもアロー関数は使えます。
この場合`add`メソッドの`this`を`counter`に固定したいので、`counter.add()`をアロー関数で囲んでみます。

```js
// addのthisをcounterに固定した関数を作成
const add = () => counter.add()

add() // 1
add() // 2
```

しっかりと`this`が`counter`になり、`this.count`がインクリメントされているのがわかります。

:::note
`this`を固定すると言えば、`bind`メソッドも使えます。
これはまさしく関数の`this`を固定するためのメソッドで、戻り値としてバインド済みの関数を返します。

先ほどのアロー関数はこのように置き換えることができます。
```js
const add = counter.add.bind(counter)

add() // 1
add() // 2
```

詳細は[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)をご覧ください。
:::

-->

## 参考リンク

`function`を使った関数の詳細は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions)です。

アロー関数の詳細は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)です。
また、[こちらの記事](https://www.bold.ne.jp/engineer-club/javascript-arrow-functions)もわかりやすいと思います。