JavaScriptの関数【関数宣言,アロー関数,無名関数,即時関数,コールバック関数,高階関数】

# はじめに

よくJavaScriptの基礎を理解せずに、ReactやTypeScriptに手を出して自滅する事例をよく耳にするので、同じ轍を踏まぬようJavaScritpの基礎をしっかり固めたいと思い今回の記事を執筆しました。

記事といっても自分自身のアウトプット理解用、備忘録なので気楽にみていただければ良いかと思います。

今回はJSの関数です。

# JavaScriptの関数

𝑦=𝑎𝑥2みたいな数学で習うものではなくて、
JSにおける関数というのは一連の処理のまとまりを指しますね。

# 関数の定義の仕方

そんな関数の作り方は大きく分けて２つ。
関数宣言と関数式に分けられます。

## 関数宣言

`function`で関数を宣言します。
関数名の後に`()`をつけると関数を実行するという意味になります。

```js
function 関数名(引数) {
  処理内容
}
```

- 基本形

```js
function hello() {
  console.log("こんにちは")
}

hello();

// 出力結果　こんにちは
```

関数`hello`を宣言した後に関数の実行を行います。

```js
function sum(a, b) {
  return a + b;
}

console.log(sum(1, 2));

// 出力結果 3
```

関数`sum`を宣言した後に関数の実行を引数1,2にして行います。

## 関数式

関数式は、`function(引数){}`という無名の関数を変数に定義したり、代入したりする記述方法になります。


```js
変数 = function(引数) {
  処理内容
}
```

- 基本形

```js
const hello = function() {
  console.log('こんにちは');
}

hello();

// 出力結果　こんにちは
```

変数`hello`に`function(){}`を代入して実行しています。

```js
const sum = function(a, b) {
  return a + b;
}

console.log(sum(1, 2));

// 出力結果　3
```

変数`sum`に`function(a, b)`という関数を代入しています。


## 関数宣言と関数式の違い

関数宣言と関数式の違いは、変数に代入するということ以外にもあります。

### 関数宣言のホイスティング

関数宣言は宣言されているコードより前に記述しても実行されるホイスティングと言われる機能があります。

- 関数宣言の場合

```js
// 関数宣言
console.log(sum(1, 2));

function sum(a, b) {
  return a + b;
}

// 出力結果　3
```


`hello`を先に実行していますが、ちゃんとホイスティングで関数を巻き上げていますので、エラーになりません。

- 関数式の場合

```js
console.log(sum(1, 2));

const sum = function(a, b) {
  return a + b;
}

// 出力結果　Uncaught ReferenceError: sum is not defined
```

関数式だと、`hello()`の時点で関数が定義されていないので、エラーとなります。


# 関数式のいろいろ


## 無名関数

無名関数はその名の通り、関数名がない定義の仕方です。

### 基本形

```js
// 無名関数
const hello = function(){
  console.log('こんにちは')
}

// 関数宣言
function hello(){
  console.log('こんにちは')
}
```

先ほどの関数宣言と関数式の説明と同じです。
関数宣言は`hello`という関数を宣言していますが、無名関数では`hello`という変数に代入して関数を定義しています。


```js
const sum = function(a, b) {
  return a + b;
}

console.log(sum(1, 2));

// 出力結果 3
```

変数`sum`に`function()`という名前のない関数を定義して代入しています。

## 即時関数

即時関数は関数を定義すると同時に実行される構文です。
関数を定義してから呼び出すという手間を省くことができます。

### 基本形

```js
// 即時関数
(function (引数) {
  // 処理
})(引数)
```


```js
const sum = (function (a, b) {
  return a + b;
}(1, 2));

console.log(sum);

// 出力結果 3
```

即時関数を使う場合は、`function()`内の外側で変数を使用することができません。
関数の中で定義した変数は関数の中でしか使用できないスコープの原理を意識しなければなりません。

## アロー関数
ES6で追加された、無名関数や即時関数において、より省略した記述をする場合に使います。

### アロー関数の記法

アロー関数は`function`省いて`() =>`といった記述によって関数を定義します。

- 引数がない場合

```js
// アロー関数
() => { 処理内容 };

// 無名関数
function() { 処理内容 };
```

- 引数が一つの場合

```js
// アロー関数
引数 => { 処理内容 };

// 無名関数
function(引数) { 処理内容 };
```

- 引数が複数ある場合

```js
// アロー関数
( 引数1, 引数2 ) => { 処理内容　};

// 無名関数
function( 引数1, 引数2 ) { 処理内容 };
```

### 基本形

まず同じ関数の定義を関数宣言と関数式で書いてみます。

- 関数宣言

```js
// 関数宣言の書き方
function greeting(name) {
  return 'Hello, ' + name;
}

console.log(greeting('ホリトモ'));

// 出力結果 Hello, ホリトモ
```

- 関数式

```js
// 関数式（無名関数）の書き方
const greeting = function(name) {
  return 'Hello, ' + name;
}

console.log(greeting('ホリトモ'));

// 出力結果 Hello, ホリトモ
```

これらを、アロー関数で書くことによって、`function`や`return`を省略して端的にかけることができます。

- アロー関数（`function`のみ省略）

```js
const greeting = (name) => {
  return 'Hello, ' + name;
}

console.log(greeting('ホリトモ'));
```

- アロー関数（`function`や`return`を省略）

```js
const greeting = name => 'Hello, ' + name;

console.log(greeting('ホリトモ'));
```

`return`を省略する場合は`{}`も省略する必要があります。

### アロー関数のメリット

この記事ではサラッと書きますが、アロー関数のメリットとしては

- 端的に短い記法で書けること
- thisやargumentsを保持せず、関数定義時に決められる

といったことがあげられます。


## コールバック関数

コールバック関数は、他の関数に引数として渡す関数をいいます。

関数はオブジェクトとして捉えられるので、他の引数に渡せるということのようですね。

### 基本形

```js
function saySomething(callback) {
  const result = callback();
  console.log(`${result}、ホリトモ!`);
}

function hello() {
  return "こんにちは";
}

saySomething(hello);

// 出力結果>> こんにちは、ホリトモ！
```

`hello`というコールバック関数を`saySomething`という関数の引数にしています。
そして`saySomething`関数内では`callback`という引数で扱われます。

主に非同期処理を行う際に使用されます。

呼び出した関数の処理が終わったあとにコールバック関数として指定した関数を実行させたい場合に使用されます。



### よくあるコールバック関数の使用例：setTimeout


setTimeout関数はJSにあらかじめ搭載されている組み込み関数です。

第一引数で渡したコールバック関数を特定の秒数を待ってから実行させます。

```js
function hello() {
  console.log("こんにちは");
}

setTimeout( hello, 3000 ) // 3秒後に出力

// 出力結果 こんにちは
```

`hello`というコールバック関数をsetTimeoutの第一引数にとっています。

また無名関数を使ってコールバック関数を定義することも可能です。

```js
setTimeout( function() {
  console.log("こんにちは"　);
}, 3000 );

// 出力結果 こんにちは
```

## 高階関数

参考：[コールバック関数/高階関数を利用する][1]
[1]:[https://www.javadrive.jp/javascript/function/index16.html]

コールバック関数とは反対に、別の関数を引数として受け取る関数のことを高階関数と呼びます。

```js
function apple(price, func){
  const name = 'りんご';
  func(name, price);
}

const price = function(name, price){
  console.log(name + ' の値段は ' + price + ' 円です。');
}

apple(200, price);

// 出力結果 りんご の値段は 100 円です。
```

`apple`という関数を呼び出す際に引数として数値のほかに別途定義した関数`price`を渡しています。

関数`apple`では受け取った関数をブロック内で呼び出しています。

このようにJavaScriptでは別途定義した関数を別の関数を呼び出す際に引数にして渡すことができます。

引数として渡される関数(`price`)のことをコールバック関数、別の関数を引数として受け取る関数(`apple`)を高階関数と呼びます。



# まとめ

| 関数名 | 内容  | 用途 |
| ----- | ---- | ---- |
| 無名関数|関数名を定義しない書き方|関数名の重複を避けたい場合|
| 即時関数|関数の定義と実行を同時にする|スコープを限定する場合<br>流用する可能性のない関数を定義する場合|
| アロー関数|無名関数を省略して書くようなもの|thisやargumentsを保持させないようにする|
| コールバック関数|別の関数に引数として渡す|promiseや非同期処理など
| 高階関数|別の関数から引数として受け取る|promiseや非同期処理など

JSの基礎を理解するには関数をよく理解する必要があります。
他にも細かいルールがあるので、別記事で書いていきたいと思います。

※記事内容は今後もアップデートしていきます。
(thisや非同期など書き足らない部分が多々あります、、、)