JS **沒有類 (ES6 前)**,只有**對象**。每個對象內部有一個隱藏屬性 `[[Prototype]]` (訪問器 `__proto__`),指向另一個對象 —— **原型對象**。屬性查找沿著原型鏈向上,直到 `null`。
| 方式 | 代碼 | 原型關係 | 適用場景 |
|---|---|---|---|
| 構造函數 + prototype | `function F(){}; F.prototype.method = ...; new F()` | `instance.__proto__ === F.prototype` | ES5 經典、庫兼容 |
| Object.create() | `const child = Object.create(parent);` | `child.__proto__ === parent` | 純原型繼承、無構造函數 |
| ES6 class | `class C { method(){} }` | `C.prototype.method`,`instance.__proto__ === C.prototype` | **現代標準**、語法糖 |
const animal = { breathe() { console.log('breathing'); } };
const dog = Object.create(animal);
dog.bark = () => console.log('woof');
dog.breathe(); // 1. dog 無 breathe → 2. animal 有 → 執行
// 原型鏈: dog → animal → Object.prototype → null
class Person {
constructor(name) { this.name = name; }
sayHi() { console.log(this.name); }
}
const p = new Person('Tom');
// 等價於
function Person(name) { this.name = name; }
Person.prototype.sayHi = function() { console.log(this.name); }
// 驗證
console.log(p.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true
console.log(Object.getPrototypeOf(p) === Person.prototype); // true
| 模式 | 核心代碼 | 優點 | 缺點 |
|---|---|---|---|
| 原型鏈繼承 | `Child.prototype = new Parent()` | 簡單 | 引用類型屬性共享、無法向父傳參 |
| 構造函數盜用 | `Parent.call(this, args)` | 解決引用共享、可傳參 | 方法無法復用 (每實例一份) |
| 組合繼承 | 盜用構造 + 原型鏈 | 兼具優點 | 調用兩次父構造函數 |
| 寄生組合繼承 (ES5 最佳) | `Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child;` | 只調用一次父構造、原型鏈純淨 | 代碼稍多 |
| ES6 extends (標準化寄生組合) | `class Child extends Parent { constructor(){ super(); } }` | **語法清晰、引擎優化、static 也繼承** | 需支持 ES6 環境 |
**原型對象是 JS 物件導向的核心**。理解 `[[Prototype]]`、`prototype`、`constructor` 三者關係,掌握 `Object.create` 與 `class extends` 兩大現代手段,避免濫用動態修改原型,即可寫出高性能、可維護的 JS 代碼。