JavaScript アロー関数とthis

# そもそもアロー関数って
ES2015（ES6）から利用可能になった新しい関数定義の構文です。
**1文しかない関数**の定義が簡素化できます。


# 定義例

引数も戻り値も無し
余談：[戻り値？返り値？](https://qiita.com/paul_soundprj/items/ffb34b28cceec7f1577b)を追求した人いました💦
```js
// いままで
const fnc1 = function () {
  console.log('SP');
}

// アロー
const arrowFnc1 = () => console.log('SP');
```

引数有り、戻り値無し
```js
// いままで
const fnc2 = function (p1) {
  console.log(p1);
}

// アロー
const arrowFnc2 = (p1) => console.log(p1);
```

引数無し、戻り値有り
```js
// いままで
const fnc3 = function () {
  return 'SP';
}

// アロー
const arrowFnc3 = () => 'SP';
```

引数有り、戻り有り
```js
// いままで
const fnc4 = function (num) {
  return num * 2;
}

// アロー
const arrowFnc4 = num => num * 2;
```

複数引数有り、戻り有り
```js
// いままで
const fnc5 = function (num,num2) {
  return num * num2;
}

// アロー
const arrowFnc5 = (num,num2) => num * num2;
```

まー、1行で書けてすっきりといった感じでしょうか。

もちろん、複数文の場合でもアロー関数定義できます。

```js
// いままで
const fnc6 = function (num,num2) {
  const ans = num * num2;
  return ans;
}

// アロー
const arrowFnc5 = (num,num2) => {
  const ans = num * num2;
  return ans;
}
```


# なんでもかんでもアロー関数定義していいわけではない。

## 制限事項
制限事項があります！

* アロー関数には、this、arguments、super への結びつけがないので、メソッドとして使用することはできません。
* アロー関数には new.target キーワードがありません。
* アロー関数は、call、apply、bind のような、一般にスコープを確立することを前提としたメソッドには適していません。
* アロー関数はコンストラクターとして使用することはできません。
* アロー関数は本体内で yield を使用することはできません。

[アロー関数式 JavaSript MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

今回は制限事項のthisについて検証しようと思います。

## アロー関数とthis

制限事項に「アロー関数には、this、arguments、super への結びつけがないので、メソッドとして使用することはできません。」
とありますが、
私は「this、arguments、super への結びつけがない」を「アロー関数ではthisは使えないのでメソッドの定義として使ってはいけない。」と理解しました。
しかし、この文だけだとよくわからないのでアロー関数でのthisについて検証します。

まずは、いままの構文でオブジェクトとメソッドを定義してみました。

```js
// オブジェクト定義
const myObject = {
  name : 'SP 太郎',
  showName: function () {
    console.log(this.name);
  }
}

myObject.showName();
```

実行すると

```console
SP 太郎
```
期待通りの表示がされました。なんの問題もありません。

アロー関数でメソッドを定義します。

```js
// オブジェクト定義
const myObject = {
  name : 'SP 太郎',
  showName: () => {
    console.log(this.name);
  }
}

myObject.showName();
```

実行すると
```console
Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'name')
```
と、thisが使えないのでエラーになりました。

本当に使えないのか？ということでthisの値を出力してみました。

```js:this確認
// オブジェクト定義
const myObject = {
  showName: () => {
    console.log(this);
  }
}

myObject.showName();
```

実行すると
```console
undefined
```
と、this変数は未定義となっているので、使えないのか分かります。

本当に本当につかえないのか？？
myObject.createSubObjectのメソッドはfunction関数定義で、
subObject.showNameのメソッドはアロー関数定義しました。

```js
// オブジェクト定義
const myObject = {
  name: 'myObject',
  createSubObject: function() {
    return {
      name: 'subObject',
      showName: () => {
        console.log(this.name);
      }
    }
  },
  showName: function() {
    console.log(this.name);
  }
}

myObject.showName();

const subObject = myObject.createSubObject();
subObject.showName();
```

実行すると
```console
myObject
myObject
```
あれ、エラーにならなかった。thisが使えた。。。。
しかし、結果がヘン。

subObject.showName();
の出力も「myObject」となっています。

ということで、
**thisが使えないのではなく、thisって何？と評価タイミングがfunction関数とアロー関数で違う**
と理解するのが正解だと思います。
上記の「this確認」ソースでthisがundefinedになったのは、myObjectがグローバル定義なので定義時にthisなんて存在しないからでしょう。

### thisの評価タイミング

**function関数（いままで）： 関数が実行される時。
アロー関数： 関数が定義される時。**

**この評価タイミングを理解したうえでfunction関数にするかアロー関数にするか決めないと、わけのわかならいバグで
填まってしまうので気をつけましょう。**

上記サンプルを解説すると
subObjectはcreateSubObjectメソッド実行時に定義しています。
createSubObjectメソッド実行時のthisは「myObject」です。
というこはsubObjectのshowName定義時のthisは「myObject」となります。
なので、subObjectのhowNameを実行した時のthisは「myObject」となり、myObject.nameの値が表示されることになります。

```js
// オブジェクト定義
const myObject = {
  name: 'myObject',
  createSubObject: function() {

    // subObjectはcreateSubObjectメソッド実行時に定義しています。
    // createSubObjectメソッド実行時のthisは「myObject」です。
    return {
      name: 'subObject',
      // subObjectのshowName定義時のthisは「myObject」となります。
      showName: () => {
        // subObjectのhowNameを実行した時のthisは「myObject」となり、myObject.nameの値が表示されることになります。
        console.log(this.name);
      }
    }
  },
  showName: function() {
    console.log(this.name);
  }
}
```

subObject.showNameもfunction関数定義にしてみます。
```js
// オブジェクト定義
const myObject = {
  name: 'myObject',
  createSubObject: function() {
    // このメソッド内のthisは「myObject」
    return {
      name: 'subObject',
      showName: function() {
        console.log(this.name);
      }
    }
  },
  showName: function() {
    console.log(this.name);
  }
}

myObject.showName();

const subObject = myObject.createSubObject();
subObject.showName();
```

subObject.showNameのthisも実行時に評価されるので、期待通りの結果となりました。
```console
myObject
subObject
```

**この検証から、クラスやオブジェクトのメソッドでは、アロー関数は使ってはいけない。となります。**

Vue.jsのメソッドの[マニュアル](https://ja.vuejs.org/api/options-state.html#methods)に
> アロー関数は this を介してコンポーネントのインスタンスにアクセスできないため、メソッドを宣言する際に使用することは避けてください。

と書いてあるのは、これらの理由からです。注意しましょう。

# じゃ、どこで使う

Array.filterとかのコールバック関数とかで、無名メソッドを定義したいときに使うのがよいかと。

```js
// いままで
const filteredList = list.filter(function (e) {
    return !e.del
});

// アロー関数
const filteredList = list.filter(e => !e.del);
```

以上です。