お笑い好きによるJavaScriptの「this」まとめ

#誰に向けて
- 全てのJS初心者に向けて
- 技術的なことばをできるだけ避けて学びたい人

#経緯
JavaScript初学者です。
パッションが湧いてきて、ここ数日間猛烈に学んでいます。

「this」の扱いが比較的とっつきづらかったので、
注意すべき点を整理しました。

#全体像（2018/05/28現在）
全体像は以下です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/228301/39e9a5b1-2467-2e72-077a-8cc3c9f94087.png)


注意すべき点をまとめて

**「アロー呼び出しABC」**

などとゴロよく呼べば
頭のメモリを節約できそうです。
（フロントエンドは諸行無常なのでいつまで持つかわかりませんが）

では、それぞれの項目を細かく見ていきます。

#呼び出し
##1.関数呼び出し
宣言した関数を`関数名()`で直接呼び出します。
関数の宣言方法は以下の記事でまとめました。

>https://qiita.com/konkipiano/items/ba9df345c17e739ecba2
お笑い好きによるJavaScriptの関数宣言まとめ

`this`は**グローバルオブジェクト**、つまり`Window`を指します。

```javascript:tsukkomi_func.js
//関数宣言
function tsukkomi(){
  console.log(this);
}

//関数呼び出し
tsukkomi();  //->Window {…}
```
###※間違えやすい点
オブジェクトの中でも、
関数呼び出しであればthisは問答無用で「Window」を指します。
**関数の宣言場所がオブジェクトの中でも外でも関係ありません。**

```javascript:tsukkomi_func_obj_out.js
//外部関数宣言
function tsukkomi(){
  console.log(this);
}

//オブジェクト宣言
var geinin = {
  tsukkomi: function(){
    //外部関数呼び出し
    tsukkomi();
  }
}

//関数呼び出し
tsukkomi();  //->Window {…}
//メソッド呼び出し(中で関数呼び出し)
geinin.tsukkomi();  //Window {…}  thisは"geinin"ではなく"Window"を指す
```

```javascript:tsukkomi_func_obj_in.js

//オブジェクト宣言
var geinin = {
  tsukkomi: function(){
    //内部関数宣言
    function tsukkomi(){
      console.log(this);
    }
    //内部関数呼び出し
    tsukkomi();
  }
}

//関数呼び出し
tsukkomi();  //->Window {…}
//メソッド呼び出し(中で関数呼び出し)
geinin.tsukkomi();  //Window {…}  thisは"geinin"ではなく"Window"を指す
```

##2.メソッド呼び出し
オブジェクトのフィールドに宣言されている関数を、
`オブジェクト名.関数名()`で呼び出します。
thisは**メソッドの親オブジェクト**を指します。

```javascript:tsukkomi_method.js
var geinin = {
  tsukkomi: function(){
    console.log(this);
  }
}
geinin.tsukkomi();  //->{tsukkomi: ƒ}  メソッドの親オブジェクト"geinin"を指す

```

##3.コンストラクタ呼び出し
コンストラクタ関数を`new`で呼び出してインスタンス生成します。
このとき、コンストラクタ関数の中のthisは**生成されるインスタンス**を指します。

```javascript:tsukkomi_const.js
//コンストラクタ関数宣言
function Geinin(boke,tsukkomi){
  this.boke = boke;
  this.tsukkomi = tsukkomi;
}

//コンストラクタ関数をnewで呼び出し
var kojima = new Geinin("oi","kojimadayo");

console.log(kojima.boke);      //->"oi"
console.log(kojima.tsukkomi);  //->"kojimadayo"

```

###※間違えやすい点
コンストラクタ関数をnewなしで呼び出す場合、「関数呼び出し」になります。
つまり、thisは「Window」を指します。

```javascript:tsukkomi_const_func.js
//コンストラクタ関数宣言
function Geinin(boke,tsukkomi){
  this.boke = boke;
  this.tsukkomi = tsukkomi;
}

//コンストラクタ呼び出し…？いえ、newが無いので「関数呼び出し」です
var kojima = Geinin("oi","kojimadayo");

//newを忘れたkojimaはすごく怒られる
console.log(kojima.boke);     //->怒られる
console.log(kojima.tsukkomi); //->怒られる

//そしてWindowにポジションを取られる
console.log(window.boke);     //->"oi"  windowが"oi"とボケてしまう
console.log(window.tsukkomi); //->"kojimadayo"  windowが"kojimadayo"とツッコんでしまう
```

#ABC(apply/bind/call)
apply/bind/callの頭文字を取りました。
これらの共通点は、**「thisを書き換える」**ということです。

目的別にわけると、

thisを書き換えて関数を実行する「apply」と「call」
thisを書き換えて関数を返す「bind」

となります。


##AとC (apply/call)はthisを上書きして関数を実行する
applyとcallはどちらも、
**thisを上書きして関数を実行します。**


```javascript:joyman_apply.js
var joymanIketani = {
  tsukkomi: "nanda koitsu~",
  doTsukkomi: function() {
    console.log(this.tsukkomi);
  }
};

var fujimoto = {
  tsukkomi: "nanda koitsu~~~~~~~~~~~~!!!!!!"
}

joymanIketani.doTsukkomi();  //->"nanda koitsu~" 池谷が持ってる"tsukkomi"が適用される
joymanIketani.doTsukkomi.apply(fujimoto);  // ->"nanda koitsu~~~~~~~~~~~~!!!!!!"  藤本が持ってる"tsukkomi"が適用される
```

上はapplyを使ったコードです。
これをcallで書き換えるには、**applyをcallに書き換えるだけです。**

```javascript:joyman_call.js
var joymanIketani = {
  tsukkomi: "nanda koitsu~",
  doTsukkomi: function() {
    console.log(this.tsukkomi);
  }
};

var fujimoto = {
  tsukkomi: "nanda koitsu~~~~~~~~~~~~!!!!!!"
}

joymanIketani.doTsukkomi();  //->"nanda koitsu~" 池谷が持ってる"tsukkomi"が適用される
joymanIketani.doTsukkomi.call(fujimoto);  // ->"nanda koitsu~~~~~~~~~~~~!!!!!!"  藤本が持ってる"tsukkomi"が適用される
```

>ちなみにこのサンプルコードで使っている
ジョイマン池谷さんとFUJIWARA藤本さんの絡みについてはこちら
https://www.youtube.com/watch?v=vkWjYgXpZJE

###※applyとcallはじゃあ何が違うのか
ブレるので、このページでは説明を省きます。
また今度まとめます。

>お笑い好きによる「apply」と「call」の違い
https://qiita.com/konkipiano/items/{TODO:記事を書いたらここにリンク貼る}

##B (bind)はthisを上書きして関数を返す
すでにあるオブジェクトのthisを書きかえて関数を返します。

```javascript:joyman_bind.js
var joymanIketani = {
  tsukkomi: "nanda koitsu~",
  doTsukkomi: function() {
    console.log(this.tsukkomi);
  }
};

var fujimoto = {
  tsukkomi: "nanda koitsu~~~~~~~~~~~~!!!!!!"
}

var fujimotoIketaniDoTsukkomi = joymanIketani.doTsukkomi.bind(fujimoto)  // ->関数を代入する
fujimotoIketaniDoTsukkomi();  //-> "nanda koitsu~~~~~~~~~~~~!!!!!!"  この変数がthisをfujimotoに書き換えたdoTsukkomi関数を持ってる
```

#アロー関数
アロー関数は、以下のように宣言する関数です。
>
```javascript:arrow.js
let pikotaro = (pen,fruits) => {
  return fruits + pen;
} //処理が1つの場合、{}を省略できる。
>
console.log(pikotaro('pen','apple'));  //->applepen
```

>参考:
お笑い好きによるJavaScriptの関数宣言まとめ
https://qiita.com/konkipiano/items/ba9df345c17e739ecba2

アロー関数で関数宣言すると、
**宣言した時点でthisを固定する**ことができます。

ちょっと何言ってるかわからないので、
通常の関数宣言とアロー関数による関数宣言を比べてみます。

```javascript:HollywoodZakoShisho_arrow.js
// hanmar kanmarをグローバルなボケとして宣言
boke = "hanmar kanmar";

// 台本ボケをする関数
function doBoke() {
  console.log(this.boke);
}

// zakoshishoがボケる関数
doZakoshiBoke = () => {
  console.log(this.boke);  // この時点でthisがwindowに固定される！
}

// この時点ではどちらのthis.bokeも"hanmar kanmar"を指す
doBoke();         //->"hanmar kanmar"
doZakoshiBoke();  //->"hanmar kanmar"

// 台本に"ai tuima te~n"と書いてあるお笑い番組
var desuyo_tv = {
  boke: "ai tuima te~n",
  geinin: doBoke,
  zakoshi: doZakoshiBoke
};

// 台本に"chikusho"と書いてあるお笑い番組
var koume_tv = {
  boke: "chikusho",
  geinin: doBoke,
  zakoshi: doZakoshiBoke
}

// desuyo_tvの進行
desuyo_tv.geinin();    //->"ai tuima te~n"  台本通りボケる
desuyo_tv.zakoshi();   //->"hanmar kanmar"  台本にセットされたボケを無視する

// koume_tvの進行
koume_tv.geinin();    //->"chikusho~"  台本通りボケる
koume_tv.zakoshi();   //->"hanmar kanmar"  台本にセットされたボケを無視する
```

通常の関数宣言で作成された`doBoke`関数は、
`desuyo_tv`でも`koume_tv`でも
ちゃんと台本通り
"ai tuima te~n"
や
"chikusho"
とボケています。
こんな番組ないですが。
つまり、**thisが呼ばれる番組によって変わる**ことがわかります。

一方で、
アロー関数で宣言した
`doZakoshiBoke`関数は、
どちらの番組の`boke`も無視して
"hanmar kanmar"
とボケています。
つまり、**呼ばれる番組に関わらずthisがWindowに固定されている**ことがわかります。

これがアロー関数によるthisの特徴です。

#まとめ
JavaScriptのthisは**アロー呼び出しABC**に注意します(2018/5/17現在)。

技術書を読むと
"thisを束縛する"
などのようなカッコイイ表現がたくさんありました。

ですが、この記事では「頭良く見られたい」という欲を必死におさえて
自分にとってイメージしやすい表現を使いました。

見識のある方からすると「なんだ？？」という部分があると思います。
そういう場合はコメント頂けると嬉しいです。

#参考にさせていただいたページ
JavaScriptの「this」は「4種類」？？
https://qiita.com/takeharu/items/9935ce476a17d6258e27
【JavaScript】アロー関数式を学ぶついでにthisも復習する話
https://qiita.com/mejileben/items/69e5facdb60781927929
Javascriptのbind関数と部分適用 〜 JSおくのほそ道 #015
https://qiita.com/mejileben/items/69e5facdb60781927929