function式とarrow式の違いをサッカー選手を呼び出しながら説明するよ

## 概要
function式とarrow式の違いをサッカー選手を使いながら軽く説明するよ


## 問題
早速、問題を出します。
aとbの違いわかりますか？

```javascript
const a = function() {
  console.log('neymar')
}

const b = () => {
  console.log('neymar')
}
```
この場合だとbのほうが合計文字数がすくなくなったくらいですかね。

次

```javascript
// let, const であればトップレベルで宣言してもwindowオブジェクトのプロパティを生成しませんが今回は問題の都合上varでいきます
// よほどのことがない限りこんな書き方をしないけどグローバルのnameに代入するために記載
// var宣言が怖い理由の一つもこれですね。

var name = '😈😈global-messhi😈😈'

const printName = function() {
  console.log('printName', this.name)
}

const arrowPrintName = () => {
  console.log('arrowPrintName', this.name)
}

const obj1 = {
  name: 'nagatomo',
  printName
}

const obj2 = {
  name: 'king-kazu',
  arrowPrintName
}

// 出力される名前はなんでしょう
obj1.printName()
obj2.arrowPrintName()
```

<details>
<summary>答え</summary>
<div>

```javascript
obj1.printName() // nagatomo
obj2.arrowPrintName() // 😈😈global-messhi😈😈
```
</div>
</details>

## アロー関数式とfunction式の違い
先程の問題の結果を見て、文字数が短くなっただけではないことはすでにわかったと思います。

`this`の指している場所が違います。

通常のfunction式の中でthisを使うと、その呼び出し元のオブジェクトを指します。

```javascript
var name = '😈😈global-messhi😈😈'

const printName = function() {
  console.log('printName', this.name)
}

const obj1 = {
  name: 'nagatomo',
  printName
}

const obj2 = {
  name: 'king-kazu',
  printName
}

obj1.printName() // 'nagatomo'
obj2.printName() // 'king-kazu'
```

なのでこの場合printName関数内で使っている`this.name`の値は呼び出し元がobj1とobj2なのかで値が異なってきます。
function式だとthisが呼ばれたタイミングで決定されちゃんと自立できていない人のような振る舞いです。
なのでfunction式は直感でわかりにくいので苦労します。

アロー関数は結論から言うと`this`は宣言された時点で、`this`を確定します。

```javascript
var name = '😈😈global-messhi😈😈'

const arrowPrintName = () => {
  console.log('arrowPrintName', this.name)  // この時点でのthisはグローバルになる
}

const obj1 = {
  name: 'nagatomo',
  arrowPrintName
}

const obj2 = {
  name: 'king-kazu',
  arrowPrintName
}

obj1.arrowPrintName() // '😈😈global-messhi😈😈'
obj2.arrowPrintName() // '😈😈global-messhi😈😈'
```

なので、呼び出し元がobj1だろうが、obj2だろうが、関係なくて直感的にthisの指している場所がわかります。

今学んだことを再確認するために、もっかい問題出します。

```javascript

class Person {
  constructor(name) {
    this.name = name
  }
  printName = function () {console.log('printName', this.name)}
  arrowPrintName = () => {console.log('arrowPrintName', this.name)}
}

const printName = function() {
  console.log('printName', this.name)
}

const arrowPrintName = () => {
  console.log('arrowPrintName', this.name)
}

class Person2 {
  constructor(name) {
      this.name = name
  }
  printName = printName
  arrowPrintName = arrowPrintName
}


const kakitani = new Person('kakitani')
const maezono = new Person2('maezono')

// 出力される名前はなんでしょう
kakitani.printName() 
kakitani.arrowPrintName()
maezono.printName()
maezono.arrowPrintName()
```

<details>
<summary>答え</summary>
<div>

```javascript
kakitani.printName()  // kakitani
kakitani.arrowPrintName() // kakitani
maezono.printName() // maezono
maezono.arrowPrintName() // 😈😈global-messhi😈😈
```
</div>
</details>

次

```javascript
const bindPrintName = function() {
  console.log(this.name)
}.bind(this) // function式をarrow関数と同じ感じでthisをつかえるようにするための魔法のコトバだよ

class Person3 {
  constructor(name) {
    this.name = name
  }
  bindPrintName = bindPrintName
}

// 出力される名前はなんでしょう
const zaccheroni = new Person3('zaccheroni')
zaccheroni.bindPrintName()
```

<details>
<summary>答え</summary>
<div>

```javascript
const zaccheroni = new Person3('zaccheroni')
zaccheroni.bindPrintName() // 😈😈global-messhi😈😈
```

</div>
</details>


## Reactでよくあるパターン
これだとボタンを押した時``Uncaught TypeError: Cannot read property 'state' of undefined``が出ます。
理由わかりますか？

```jsx
export default class Hoge extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'zico'
    };
  }

  handlePrintName() {
    const { name } = this.state;
    return name
  }

  render() {
    const { name } = this.state;

    return (
      <button onClick={this.handlePrintName}>
        print name
      </button>
    );
  }
}
```

### 解決方法
`handlePrintName()`をアロー関数にする

```javascript
  // 変更前
  handlePrintName() { // これでthisが定まっていない
    const { name } = this.state;  
    return name
  }
  // 変更後
  handlePrintName = () => { // これでthisをHogeにbind
    const { name } = this.state;  
    return name
  }
```

ただReactの場合これには問題点があります。

レンダー内でアロー関数を利用するとコンポーネントがレンダーされるたびに新しい関数が作成されるため、子コンポーネントでReact.memoやPureComponentを使ってた場合に正しく比較されなくなる

ClassComponentでは`bind(this)`を使う場合が多い

```jsx

export default class Hoge extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'zico'
    };
  this.handlePrintName  = this.handlePrintName.bind(this)
  }

  handlePrintName() {
    const { name } = this.state;
    return name
  }

  render() {
    const { name } = this.state;

    return (
      <button onClick={this.handlePrintName}>
        print name
      </button>
    );
  }
}
```

## 参考記事
[JavaScriptの「this」は「4種類」？？](https://qiita.com/takeharu/items/9935ce476a17d6258e27)
[JavaScript の this を理解する多分一番分かりやすい説明](https://qiita.com/takkyun/items/c6e2f2cf25327299cf03)