
結論先講
JavaScript 沒有真的 class,ES6 的 class 關鍵字是 prototype 的語法糖。
真正的運作是 prototype chain:每個物件有個隱藏的 __proto__ 指標,指向它的「原型」。取屬性時沿著 chain 往上找,直到找到或到 null。
const arr = [1, 2];
arr.map(...); // Array.prototype.map
// arr → Array.prototype → Object.prototype → nullClass 語法讓 code 看起來像 Java,但底層機制完全不同。搞懂 prototype chain 才能解釋:
- 為什麼
instance.method()能跑 - 為什麼繼承實際是「連 prototype 成鏈」
- 為什麼 React 社群現在偏好 function component 而非 class component
Prototype Chain:物件的家族樹
const obj = { name: 'A' };
console.log(obj.__proto__); // Object.prototype
console.log(obj.toString()); // 從 Object.prototype 繼承而來每個物件都有 __proto__(現代 API:Object.getPrototypeOf(obj))。
鏈怎麼查
const arr = [1, 2, 3];
// arr.__proto__ === Array.prototype
// Array.prototype.__proto__ === Object.prototype
// Object.prototype.__proto__ === nullarr.map(...) 的流程:
arr自己有map?沒有Array.prototype有map?有!用它- 用
arr當this呼叫該map
這就是「方法繼承」的本質——鏈式查找。
class 是什麼
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hi, ${this.name}`;
}
}
const u = new User('Alice');
u.greet(); // "Hi, Alice"看起來像 Java。實際上 JS 做了這些事:
function User(name) {
this.name = name;
}
User.prototype.greet = function() {
return `Hi, ${this.name}`;
};
const u = new User('Alice');
// u.__proto__ === User.prototypeclass 只是包裝 constructor function + 在 prototype 上加方法。
驗證
typeof class Foo {} // 'function'
class Foo {}.prototype // { constructor: class Foo }Class 就是 function。
new 做了什麼
const u = new User('Alice');等同:
const u = {}; // 1. 建立空物件
Object.setPrototypeOf(u, User.prototype); // 2. 連上原型鏈
User.call(u, 'Alice'); // 3. 用 u 當 this 執行 constructor
// 4. 回傳 u(constructor 沒明確 return 時)所以 u 能用 User.prototype.greet 因為鏈連上了。
繼承:連兩條鏈
class Admin extends User {
constructor(name, role) {
super(name);
this.role = role;
}
whoAmI() {
return `${this.name} (${this.role})`;
}
}
const a = new Admin('Bob', 'superuser');
a.greet(); // 從 User.prototype 繼承
a.whoAmI(); // Admin.prototype 自己的Prototype 鏈:
a.__proto__ === Admin.prototype
Admin.prototype.__proto__ === User.prototype
User.prototype.__proto__ === Object.prototype
a.greet() 查找過程:
a沒有 greetAdmin.prototype沒有User.prototype有!用它
super 做什麼
super() 呼叫父類的 constructor,super.method() 呼叫父類的方法。
class Admin extends User {
greet() {
return super.greet() + ' (admin)'; // 呼叫 User.prototype.greet
}
}靜態方法 vs 實例方法
class MathUtils {
static square(n) { return n * n; } // 靜態:class 本身的方法
cube(n) { return n * n * n; } // 實例:prototype 上
}
MathUtils.square(5); // 25 ✅
new MathUtils().cube(5); // 125 ✅
MathUtils.cube(5); // ❌ TypeError
new MathUtils().square(5); // ❌ TypeError在哪裡?
static方法 → 直接掛在 class 本身(MathUtils.square)- 實例方法 → 掛在
MathUtils.prototype.cube
實戰:工具函式用 static(不用每次 new);需要 state 的邏輯用實例。
Private Field(現代)
傳統 JS 沒 private,大家用命名慣例:
class User {
constructor() {
this._password = '...'; // 底線表示「請不要碰」
}
}現代 JS(ES2022)有真的 private field:
class User {
#password; // 真 private
constructor(pw) {
this.#password = pw;
}
check(pw) {
return this.#password === pw;
}
}
const u = new User('secret');
u.#password; // ❌ SyntaxError(外部存取不到)比 TypeScript 的 private 強——TS 只是編譯期檢查,runtime 仍可存取。# 是 runtime 保護。
為什麼 React 拋棄 class 轉 function
// 老 class 寫法
class Counter extends React.Component {
state = { count: 0 };
increment = () => this.setState({ count: this.state.count + 1 });
render() { return <button onClick={this.increment}>{this.state.count}</button>; }
}
// 新 function 寫法
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}Function 為什麼贏
- 沒有
this綁定問題(閉包直接抓變數) - Code 更短(不用 constructor、bind、lifecycle 方法)
- Hooks 更強(useEffect、useMemo、useContext 組合力強)
- HMR 友善(function 重新載入比 class 可靠)
- TypeScript 推斷更好
2026 年,React / Vue 3 / Solid 都主推 function-based component。class 只在讀老 code 接觸。
但你仍要懂 prototype — 因為 JS 內建型別(Array、Map、Set、Date)都用 prototype,你寫 array.filter(...) 就在用 prototype chain。
實戰:什麼時候還會用 class
雖然 component 不用了,這些場景仍適合 class:
- Model / Entity 定義(DDD 專案)
- Error 自訂(
class ValidationError extends Error) - 大型 state 機器 / service(有多個相關方法 + 狀態)
- Web Components(
class Foo extends HTMLElement) - 工具 class(例如
class Cache { ... })
但不要強求。很多 class 都能用 factory function + closure 實作,code 更短、更好測。
Factory Function:Class 的替代方案
// Class
class Counter {
constructor() { this.count = 0; }
increment() { this.count++; }
get() { return this.count; }
}
// Factory function(更簡潔、沒 this 問題)
function createCounter() {
let count = 0;
return {
increment: () => count++,
get: () => count,
};
}
const c = createCounter();
c.increment();
c.get(); // 1Factory 優點:
count真 private(closure 保護)- 沒
this綁定問題 - 可以 TypeScript 推斷介面
缺點:
- 每個 instance 方法都是新函式(class 只有一份在 prototype)
- 大量 instance 時記憶體較高
實戰:少量 instance 用 factory,大量 instance(10k+)才考慮 class。
實戰 Checklist
- 懂 prototype chain 是查找機制,不是繼承的「複製」
-
class是 syntactic sugar,底層仍是 prototype - React / Vue 3 優先用 function component,class 只讀老 code
- 自訂 Error、Web Components 仍用 class
- 少量 instance 考慮 factory function(更簡潔)
- Private 用
#field(真 runtime 保護) - 懂
super()要在 derived constructor 裡先呼叫才能用this
相關文章
- this 綁定 — class 方法的 this 陷阱
- Closure — Factory function 的基礎
- JS 子 Roadmap
- Frontend Roadmap
