はじめに
JavaScript を本質から理解しようとすると必ずぶつかるのが Class と Prototype。
一見すると「クラスベース言語みたいに見える」JavaScript だけど、実際にはまったく別の進化を遂げた プロトタイプベース言語だ。
本記事では、次のポイントを軸に “わかったつもり” を完全に卒業することを目指す。
- Prototype(プロトタイプ)とは何か
- Prototype Chain の動き
- Class 文法の正体(=シンタックスシュガー)
- Class 継承(extends)の内部動作
- new の内部処理
- どんなときに prototype を理解しておくべきか
- セキュリティ(Prototype Pollution)とのつながり
1. Prototype(プロトタイプ)とは何か
JavaScript のすべてのオブジェクトは、内部に [[Prototype]] というリンクを持っている。
これは「親オブジェクト」だと考えるとイメージがつきやすい。
プロトタイプの役割
- オブジェクトが持っていないメソッド・プロパティを探す場所
- 複数のオブジェクト間でメソッドを共有し、メモリ効率を高める仕組み
- いわゆる「継承」に相当する機能を実現する土台
例
const obj = {};
console.log(obj.__proto__ === Object.prototype); // true
obj の親は Object.prototype。
このチェーンは必要に応じてどんどん上に伸びる。
2. Prototype Chain(プロトタイプチェーン)
プロトタイプは 1 つのリンクだが、親にもさらに親がいる。
この連鎖を Prototype Chain と呼ぶ。
myObj → Person.prototype → Object.prototype → null
JavaScript のプロパティ探索はこの順で行われる。
- 自分自身にある?
- なければ prototype を見る
- prototype にないなら prototype の prototype を見る
- 最後は
nullに到達して終了
3. Class の正体:Prototype を包んだ「気の利いた皮」
ES6 で Class が導入されたとき、多くの JS 開発者が「ついに JS がクラスベース言語に!」と勘違いした。
しかし実際は、内部は Prototype を使った仕組みのまま。
Class の例
class Person {
constructor(name) {
this.name = name;
}
sayHi() {
console.log(`Hi, I'm ${this.name}`);
}
}
内部ではこう変換されている
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function() {
console.log(`Hi, I'm ${this.name}`);
};
はい、中身はただの prototype 操作。
Class は“読みやすくしただけ”というのが真実。
4. Class 継承(extends)の内部動作
class Student extends Person {
study() {
console.log("studying...");
}
}
内部では次のように処理される:
Student.prototype.__proto__ = Person.prototype
つまり prototype chain を接続しているだけ。
5. new キーワードの内部処理
new Person("Anna") を実行すると、実際には 4 ステップの秘密の儀式が行われている。
1. 新しい空オブジェクト {} を作る
2. そのオブジェクトの [[Prototype]] を Person.prototype に設定
3. constructor を呼んで this にプロパティをセット
4. this を返す
コードにすると:
function newLike(constructor, ...args) {
const obj = Object.create(constructor.prototype); // step 1 & 2
const result = constructor.apply(obj, args); // step 3
return typeof result === "object" ? result : obj; // step 4
}
JavaScript は、この内部動作で「クラス風の挙動」を演出しているだけ。
6. 実務で prototype を理解するべき理由
Class を使っても、問題は prototype レベルで発生する
- 継承のバグは prototype chain が原因
- メモリリークの調査で prototype を追う必要がある
- this のバインド問題(特に React)も prototype と関係する
- セキュリティの Prototype Pollution は prototype の構造理解が必須
JS を深く理解する人は必ず prototype にたどり着く
React, Vue, Node.js の内部でも prototype は日常的に使われている。
7. セキュリティ:Prototype Pollution とのつながり
Prototype を理解していないと攻撃の危険性も見抜けない。
例:
const payload = {
"__proto__": {
admin: true
}
};
Object.assign({}, payload);
console.log({}.admin); // true
__proto__ を書き換えることで 全オブジェクトの prototype が汚染される(Polluted)。
→ 本質を理解していると「なぜこうなるか」が直ちに理解できる。
はじめに
JavaScript を表面ではなく“本体”から理解したいなら、Prototype を避けることはできない。
Class は読みやすさのための糖衣構文だけど、動作はすべて Prototype 上で行われている。