`this` を完全に理解する：JavaScriptの呼び出しコンテキスト全パターン整理

## 概要

`this` は JavaScript最大の罠とも言われる。  
なぜならその挙動は、**“関数の中身”ではなく、“関数の呼ばれ方”で決まる**からだ。

`this` の正体を見極めるには、**呼び出しコンテキストとバインディングのルール**を体系的に理解する必要がある。  
この記事では、JavaScriptにおける `this` の動的バインディングのルールと、それに対応するコード設計を構造的に解説する。

---

## 対象環境

```text
ES5〜ES2023対応のJavaScript環境（Node.js / ブラウザ）
```

---

## `this` の正体：**“呼び出し元のコンテキスト”を参照する特殊キーワード**

- 実行時に動的に決定される
- **関数の宣言時ではなく、呼び出し時に決まる**
- `this` の中身は、**「誰が呼び出したか」によって変化**する

---

## 呼び出しパターン別 this の挙動一覧

| 呼び出し方                             | `this` の参照先                          |
|----------------------------------------|------------------------------------------|
| 通常の関数呼び出し（非 strict）        | グローバルオブジェクト（`window` / `global`） |
| 通常の関数呼び出し（strictモード）     | `undefined`                              |
| メソッド呼び出し                       | メソッドの所有オブジェクト               |
| コンストラクタ（`new`）呼び出し        | 新しく生成されたインスタンスオブジェクト |
| 明示的バインド（`call` / `apply`）     | 第一引数で指定したオブジェクト           |
| 永続バインド（`bind`）                 | `bind()` で指定されたオブジェクト        |
| イベントリスナー（DOM）                | イベント発火元のDOM要素                  |
| アロー関数                              | **外側スコープの `this` を継承**         |
| クラスメソッド（通常）                 | インスタンス                             |
| クラスの静的メソッド                   | クラス自身                               |

---

## 各パターンを実例で確認

### ✅ 通常関数（非strict）

```js
function show() {
  console.log(this); // グローバル（window / global）
}
show();
```

---

### ✅ strictモード下

```js
'use strict';
function show() {
  console.log(this); // undefined
}
show();
```

---

### ✅ メソッドとして呼び出す

```js
const obj = {
  name: 'Alice',
  greet() {
    console.log(this.name); // 'Alice'
  }
};
obj.greet();
```

---

### ✅ アロー関数

```js
const obj = {
  name: 'Alice',
  greet: () => {
    console.log(this.name); // undefined（外側の this → グローバル）
  }
};
obj.greet();
```

→ アロー関数は **`this` を自動的に閉じ込める（レキシカルスコープ）**

---

### ✅ イベントリスナー内の this

```js
button.addEventListener('click', function () {
  console.log(this); // クリックされたボタン要素
});
```

→ ただし、アロー関数で書くと this が変わる：

```js
button.addEventListener('click', () => {
  console.log(this); // 外側の this（＝window or undefined）
});
```

---

### ✅ `call`, `apply`, `bind` による明示的指定

```js
function show() {
  console.log(this.name);
}
const user = { name: 'toto' };

show.call(user); // 'toto'
show.apply(user); // 'toto'
const bound = show.bind(user);
bound(); // 'toto'
```

---

### ✅ コンストラクタでの this

```js
function User(name) {
  this.name = name;
}
const u = new User('toto');
console.log(u.name); // 'toto'
```

---

### ✅ クラスメソッドでの this

```js
class Person {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log(this.name);
  }
}
const p = new Person('toto');
p.greet(); // 'toto'
```

---

## よくあるバグパターンと対策

### ❌ this が undefined / 意図外になる

```js
const obj = {
  count: 0,
  increment() {
    setTimeout(function () {
      this.count++;
    }, 100);
  }
};
```

→ ✅ 対策：アロー関数 or `bind(this)`

```js
setTimeout(() => {
  this.count++; // 外側の this を使う
}, 100);
```

---

## this 設計の原則

| シーン                       | 推奨する this 設計               |
|------------------------------|----------------------------------|
| コールバック関数             | アロー関数でスコープを固定       |
| コンストラクタ / クラス      | 通常の関数（`this`を使う）       |
| 状態を閉じ込めたい関数       | アロー関数を使わずクロージャで管理 |
| イベントリスナー             | function + bind(this) or クラスで管理 |
| ライブラリ間の橋渡し         | `call` / `apply` で明示的に指定   |

---

## 結語

`this` は魔法ではない。  
それは、「**どこから呼ばれたのか**」という**文脈（コンテキスト）そのもの**だ。

thisを理解するとは、「関数が、誰に責任を持って処理を行っているのか」を理解することでもある。  
関数の本質は処理ではない。**責任の構造**である。

すべての this を意図して使う。  
それこそが、JavaScriptを“制御できる”状態の第一歩だ。