プロトタイプ(プロトタイプチェーン)と継承を「初心者向け」に噛み砕いて、たっぷり例付きで解説する。ポイントを押さえて、実際に試せるコードも入れるから手を動かしてみて。
プロトタイプと継承 — 概要(超かんたん)
- オブジェクトは「プロトタイプ(親オブジェクト)」を持てる。
あるオブジェクトにプロパティやメソッドが無いときは、その親(プロトタイプ)を順に探していく仕組みが プロトタイプチェーン。 - この仕組みによって 「同じ機能を何度も書かずに共有できる」=継承 が実現される。
例えると:部屋(オブジェクト)に椅子(プロパティ)が無ければ、隣の倉庫(プロトタイプ)を見に行って借りる感じ。
プロトタイプチェーン探索のアニメーション(親から順に探す様子)

なぜ大事?(メリット)
- メモリを節約できる(共通メソッドをひとつだけ持たせる)
- オブジェクトの振る舞い(メソッド)をまとめて管理できる(変更は親だけ)
実際にどう動くか:簡単なコードで理解する
const parent = {
greet() {
console.log("hello from parent");
}
};
const child = Object.create(parent);
child.name = "child";
child.greet(); // "hello from parent"
JavaScript動き:
child.greetを呼ぶchildにgreetが無い → 次にchildのプロトタイプ(ここではparent)を探すparentにgreetがある → それを使う
Object.create(parent) は「parent をプロトタイプにした新しいオブジェクト」を作る便利な方法。
prototype と [[Prototype]] の違い(混乱しやすいポイント)
- 関数オブジェクト(コンストラクタ関数)には
.prototypeプロパティがある。
例:function Person(){}→Person.prototypeはnew Person()が参照する「プロトタイプの設計図」。 - 作られたオブジェクト自体は内部スロット
[[Prototype]](多くの環境で__proto__として見える)を持つ。これは実行時に次に探索する「親オブジェクト」を指す。
図(イメージ):
Person (function)
└─ .prototype ---> { sayHi: function() {...} }
alice (object) --[[Prototype]]--> Person.prototype
JavaScriptコード例(コンストラクタ関数と new):
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log(this.name);
};
const alice = new Person("Alice");
alice.sayName(); // "Alice"
JavaScriptnew Person("Alice")は内部でPerson.prototypeをaliceのプロトタイプにセットする。
instanceof とプロトタイプ
obj instanceof Constructor は、Constructor.prototype が obj のプロトタイプチェーンのどこかに存在するかをチェックする。
alice instanceof Person; // true
JavaScripthasOwnProperty とプロトタイプ由来のプロパティの見分け方
obj.propでプロパティが見つかっても、それが自分自身(自身のプロパティ)か、プロトタイプから来たものかは別。- 自身のプロパティか確認するには:
alice.hasOwnProperty("name"); // true
alice.hasOwnProperty("sayName"); // false(sayName は prototype 側)
JavaScriptプロパティの探索(シャドウイング)
- 子オブジェクトに同じ名前のプロパティがあると、プロトタイプ側の同名プロパティは見えなく(上書きされて)なる。これをシャドウイング(shadowing)という。
Person.prototype.age = 0;
alice.age; // 0 (proto の値)
alice.age = 30; // 子に age を作る(シャドウ)
alice.age; // 30
// Person.prototype.age は依然 0 のまま
JavaScriptObject.create vs コンストラクタ関数(使い分け)
Object.create(proto):プロトタイプを直接指定して新しいオブジェクトを作る(シンプル・明示的)。- コンストラクタ関数 +
new:オブジェクトに初期化処理(プロパティの設定)を組み込める。クラス構文の裏で使われる考え方。
どちらもプロトタイプ継承を使う手段だけど、最近は読みやすさのために ES6 の class 構文を使うことが多い(下で説明)。
ES6 の class 構文(見た目はクラスだがプロトタイプを使う)
class はプロトタイプ継承の「シンタックスシュガー(書きやすくしただけ)」で、内部的にはプロトタイプを使っている。
class Person {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
const bob = new Person("Bob");
bob.sayName(); // "Bob"
JavaScriptPerson.prototype.sayName に相当するメソッドは class のメソッドとして定義され、全インスタンスで共有される。
よくある誤解・注意点(初心者がつまずきやすい)
- プロパティを書き換えると全インスタンスに影響が出る?
- prototype にある オブジェクト を直接変更すると、参照しているすべてのインスタンスに影響する(共有参照の副作用)。
- 例:
Person.prototype.tags = []とすると全インスタンスで同じ配列を共有する → 予期せぬデータ混入に注意。
thisの値は呼び出し方で決まるobj.method()のときはthis === obj。でもconst f = obj.method; f();のように取り出すとthisがundefined(strict mode)やglobalに変わる。bind,call,applyでthisを明示的に固定できる。
for...inはプロトタイプ上のプロパティも列挙するfor...inは列挙可能なプロパティをプロトタイプチェーン含めて列挙するので、通常はhasOwnPropertyと組み合わせて使う。
- プロトタイプチェーンは実行時に辿られる(動的)
- つまり、後から
someProto.newMethod = ...と追加すれば、既に存在するインスタンスからも参照可能になる。
- つまり、後から
まとめ
- 継承 = オブジェクトが別のオブジェクトを「親」にしてプロパティ/メソッドを借りる仕組み。
- JavaScript の継承は プロトタイプチェーン による(クラス構文はそのラッパー)。
- 使うときは「どこにプロパティを置くか(自分側か prototype 側か)」で動作が大きく変わることを意識して。
- 練習(3問 — 手を動かそう)
const a = {x:1}; const b = Object.create(a); console.log(b.x);の出力は?(答え:1)- コンストラクタ関数で
greetメソッドを全インスタンスで共有する書き方を実装してみて。 Person.prototype.arr = []を定義して、p1.arr.push(1)したときp2.arrはどうなる? なぜ?
