JavaScriptのthisを8種類試してみた


## はじめに
JavaScriptの`this`の使い方で苦戦をしたので、整理と備忘録のために8種類の`this`の動きを試してみました。
主にこちらの2つの記事を参考に勉強した内容の記事となります。
- [ui's blog JavaScript JavaScriptの"this"を完全解説！！【開眼JavaScriptまとめ】](https://ui.appleple.blog/JS/javascript-this.html)
- [JavaScriptのthisについて](https://qiita.com/hu-yu/items/74529effd585de1d70ca#default-this-context--object-literalsthis)


## 1. トップレベル（関数外）のthis
**結論**
`this`の参照先 = グローバルオブジェクト= windowオブジェクトとなる。<br>

```JavaScript: トップレベル（関数外）のthis
"use strict";

console.log(this) // window

this.alert('Hello World'); // window
```
**consoleの表示**
![consoleの表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/ef09f3c0-f00c-c367-b015-47c18c7db3d7.png)
**htmlの表示**
![this.alert.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/3e9c948f-05e1-ae90-baf7-a11cee005bd3.png)

※ non-strictモードの場合も結果は同じでした。

## 2.関数内のthis
**結論**
strictモード：`this`の参照先 = `undefined`
non-strictモード：`this`の参照先 = window

**strictモード**
```javascript: 関数内のthis(strictモード)
"use strict";

function consoleDisplay() {
    console.log(this);
}
consoleDisplay(); // undefined
```
**consoleの表示**
![consoleの表示_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/e754999e-d8c5-d29d-4763-8ada6b89fe17.png)

**non-strictモード**
```javascript: 関数内のthis(non-strictモード)
function consoleDisplay() {
    console.log(this);
}

consoleDisplay(); // window
```
**consoleの表示**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/41bb77cc-2320-4cf9-8797-75664e82492d.png)

## 3.アロー関数内のthis
**結論**
`this`の参照先 = 呼び出し元のオブジェクト

2パターン試します。

```javascript: トップレベルで宣言したアロー関数
let testArrowFunction = () => {
    console.log(this);
}
testArrowFunction(); // window (呼び出し元のオブジェクト)
```

**consoleの表示**
![consoleの表示_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/df4347ab-7a84-bf3e-69d8-4171009136ff.png)


```javascript: オブジェクト内のアロー関数
let test = {
    testMethod() {
        let consoleDisplay = () => {
            console.log(this);
        }
        consoleDisplay();
    }
}
test.testMethod(); // testMethod (呼び出し元のオブジェクト)
```

**consoleの表示**
![consoleの表示_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/11cde0fc-0f97-86a8-6fb8-c23bfbad3a6c.png)

## 4.オブジェクトの関数内のthis
**結論**
`this`の参照先 = グローバルオブジェクト= windowオブジェクト

```javascript: オブジェクトの関数内のthis
let test = {
    testMethod() {
        let consoleDisplay = function() {
            console.log(this);
        }
        consoleDisplay();
    }
}
test.testMethod(); // window
```
**consoleの表示**
![consoleの表示_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/e8dd781a-ef1d-5948-f2ca-919b38325356.png)

## 5.call(), apply()で呼び出した際のthis
**結論**
`this`の参照先 = call(), apply()の引数で指定した先

```javascript: call(), apply()で呼び出した際のthis
const testMethod = function (a, b) {
    console.log(this);
    console.log(a + b);
}

const testObject = {
    testMethod: testMethod
}

testMethod(); // window // NaN
testMethod.call(null, 1, 2); // window // 3
testMethod.apply(null, [3, 4]); // window // 7
testMethod.call(testMethod, 5, 6); // testMethod // 11
testMethod.apply(testMethod, [7, 8]); // testMethod // 15
testMethod.call(testObject, 9, 10); // testMethod // 19
testMethod.apply(testObject, [11, 12]); // testMethod // 23
```

## 6.bind()で呼び出した際のthis
**結論**
`this`の参照先 = bind()の引数で指定した先

```javascript: bind()で呼び出した際のthis
function test(){
    console.log("thisの値：" + this);
}

const obj = test.bind("今日のご飯")
obj(); // thisの値：今日のご飯
```
**consoleの表示**
![consoleの表示_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/b84e0829-ce75-6fe9-9e31-cfc35f801903.png)

## 7.イベントハンドラー / イベントリスナー内のthis
**結論**
無名関数で呼び出した`this`の参照先 = イベントの発生元
アロー関数で呼び出した`this`の参照先 = 呼び出し元のオブジェクト

3パターン試します。
```html: html側でボタンを設定
<button id="btn">表示</button>
```

```javascript: 無名関数で呼び出したthis
document.getElementById('btn').addEventListener('click', function() {
    console.log(this) // <button id="btn">表示</button>
})
```
**consoleの表示**
![consoleの表示_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/734aec31-bf86-500f-c38e-85874949a023.png)

```javascript: アロー関数で呼び出したthis
document.getElementById('btn').addEventListener('click', () => {
    console.log(this) // window
})
```
**consoleの表示**
![consoleの表示_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/9c30148b-f186-6698-403d-0e35395e20d6.png)

```javascript: オブジェクト内のアロー関数で呼び出したthis
const testObj = {
    testMethod: function () {
        document.getElementById('btn').addEventListener('click', () => {
            console.log(this) // testMethod
        })
    }
}
testObj.testMethod();
```
**consoleの表示**
![consoleの表示_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/19cfe895-d85e-97ef-a208-a41075abe6af.png)

## 8.コンストラクターで呼び出した際のthis
**結論**
`this`の参照先 = 生成されたインスタンス

2パターン試します。

```javascript: 
const Food = function(name, price){
    this.name = name;
    this.price = price;
}

const curry = new Food("Curry", 850);
console.log(curry.name); // Curry
console.log(curry.price); // 850
```
**consoleの表示**
![consoleの表示_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/86ca9c61-e7ec-3aaf-89a3-e3e1f9d0a809.png)

```javascript: クラス内のコンストラクターで呼び出した際のthis
class Food {
    constructor(name, price){
        this.name = name;
        this.price = price;
    }
}

const curry = new Food("Curry", 850);

console.log(curry.name); // Curry
console.log(curry.price); // 850
```
**consoleの表示**
![consoleの表示_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783584/8b2556a1-f660-c2c7-b7ab-172bf07bfebf.png)

## まとめ
大よその`this`についての理解が深まりました。
より詳しく知りたい方は以下のサイトをご覧ください。

## 参考資料
- [ui's blog JavaScript JavaScriptの"this"を完全解説！！【開眼JavaScriptまとめ】](https://ui.appleple.blog/JS/javascript-this.html)
- [JavaScriptのthisについて](https://qiita.com/hu-yu/items/74529effd585de1d70ca#default-this-context--object-literalsthis)
- [Understanding "This" in JavaScript | Codementor](https://www.codementor.io/@dariogarciamoya/understanding--this--in-javascript-du1084lyn)
- [Understanding "this" in javascript with arrow functions | Codementor](https://www.codementor.io/@dariogarciamoya/understanding-this-in-javascript-with-arrow-functions-gcpjwfyuc)