JavaScriptのプロトタイプチェーン完全理解：継承構造・__proto__・constructorの正体を紐解く


## 概要

JavaScriptは **プロトタイプベースの継承モデル** を採用しており、クラスベースとは異なるメカニズムでオブジェクト同士の関係性が構築される。  
この関係を支えるのが「**プロトタイプチェーン**」であり、以下のような現象を支配している：

- なぜオブジェクトに定義していない `toString()` が呼べるのか
- 関数に自動的に `prototype` プロパティが存在する理由
- `__proto__` と `prototype` の違い
- `new` キーワードが内部的に何をしているのか

この記事では、**プロトタイプチェーンの構造・設計・使い所・落とし穴**を徹底的に整理する。

---

## プロトタイプベースの継承とは？

すべてのオブジェクトは、別のオブジェクト（**プロトタイプ**）を参照している。  
プロパティやメソッドが見つからなかった場合、**その参照先をたどって探索**が行われる。  
この参照の連鎖が「**プロトタイプチェーン**」。

```js
const obj = {};
obj.toString(); // ✅ Object.prototype.toString が参照されている
```

---

## 基本構造

```js
const a = {};
console.log(a.__proto__ === Object.prototype); // true
```

- `a` 自体は `toString` を持たない
- `a.__proto__`（非推奨だが慣例的に使用） を辿ると `Object.prototype` に到達
- 最終的に `Object.prototype.__proto__ === null` → チェーンの終端

---

## 関数と prototype の関係

```js
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  return `${this.name} makes a sound`;
};

const dog = new Animal('Pochi');
dog.speak(); // 'Pochi makes a sound'
```

### ✅ 内部的な流れ

```text
1. Animal.prototype が dog.__proto__ に代入される
2. dog.speak() → dog.__proto__.speak() を参照
```

---

## `__proto__` と `prototype` の違い

| 用語            | 意味                                     |
|------------------|------------------------------------------|
| `obj.__proto__`  | インスタンスが参照するプロトタイプ       |
| `Func.prototype` | 関数コンストラクタが作るインスタンスの参照先 |
| `obj.constructor`| インスタンスを生成した関数（Func）        |

```js
dog.__proto__ === Animal.prototype;     // ✅ true
Animal.prototype.constructor === Animal; // ✅ true
```

---

## `new` キーワードの内部的な動作

```js
const d = new Animal('Toto');
```

内部的には以下の処理が行われている：

```js
function newOperator(Cls, ...args) {
  const instance = Object.create(Cls.prototype);
  Cls.apply(instance, args);
  return instance;
}
```

→ ✅ `Object.create()` によりプロトタイプを接続  
→ ✅ `apply` によりインスタンスの初期化

---

## プロトタイプチェーンの視覚イメージ

```text
dog --> Animal.prototype --> Object.prototype --> null
```

---

## 継承の拡張：プロトタイプによる多段階継承

```js
function Dog(name) {
  Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function () {
  return `${this.name} barks`;
};

const d = new Dog('Pochi');
d.speak(); // Pochi barks
```

---

## クラス構文との接続点（ES6以降）

```js
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    return `${this.name} makes a sound`;
  }
}

class Dog extends Animal {
  speak() {
    return `${this.name} barks`;
  }
}

const d = new Dog('Toto');
d.speak(); // Toto barks
```

→ ✅ この構文は糖衣構文であり、内部ではプロトタイプチェーンが構築されている

---

## よくある誤解

### ❌ `prototype` はインスタンスに存在しない

```js
console.log(d.prototype); // undefined
```

→ ✅ `prototype` は**関数にしか存在しないプロパティ**

---

### ❌ `__proto__` は非標準（とはいえ使われがち）

→ ✅ 安全には `Object.getPrototypeOf(obj)` を使う

---

## 設計におけるプロトタイプの使い所

| 目的                         | 適切な設計手段                   |
|------------------------------|----------------------------------|
| 複数のインスタンスで同一メソッドを共有したい | `Func.prototype.method = ...` |
| クラスベースの継承を書きたい | ES6 `class` / `extends` 構文    |
| プロトタイプチェーンを明示制御したい | `Object.create()` / `setPrototypeOf()` |
| 高速な共有メソッド設計       | `prototype` ベースの設計        |

---

## 結語

JavaScriptのオブジェクト設計は、「クラスベースの模倣」ではない。  
それは**プロトタイプという連鎖構造により、オブジェクト間の振る舞いを合成する設計**である。

- `__proto__` は参照先  
- `prototype` は生成元の青写真  
- `new` は両者をつなぐトリガー

**構造を理解すれば、継承の挙動は“必然的”に説明できるようになる。**  
クラス構文に頼る前に、**プロトタイプという“原点”を設計として理解せよ。**