
JavaScript 在 ECMAScript 2015(ES6)正式引入 class 語法,作為既有 prototype 繼承模型的語法糖(syntax sugar)。本質上,JavaScript 仍然是以 prototype 為核心的語言,但 class 大幅改善了可讀性與可維護性,讓開發者能以更接近傳統物件導向(OOP)的方式來組織程式碼。因此,理解 JavaScript class 的設計定位與實際使用情境,會對大型前端或全端專案非常有幫助。
JavaScript 使用 class 關鍵字來宣告類別,並透過 constructor 定義初始化行為:
js1class Person { 2 constructor(name, age) { 3 this.name = name; 4 this.age = age; 5 } 6 7 greet() { 8 console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); 9 } 10} 11 12const john = new Person("John", 30); 13john.greet();
注意事項
constructor 在 new 時會自動呼叫在瞭解 class 和 prototype 之前,有一點重要的前提:class 並沒有取代 prototype,只是包裝它。
js1function Person(name, age) { 2 this.name = name; 3 this.age = age; 4} 5 6Person.prototype.greet = function () { 7 console.log(`Hello, my name is ${this.name}`); 8};
js1class Person { 2 constructor(name, age) { 3 this.name = name; 4 this.age = age; 5 } 6 7 greet() { 8 console.log(`Hello, my name is ${this.name}`); 9 } 10}
| Prototype | Class | |
|---|---|---|
| 可讀性 | 偏低 | 高 |
| 繼承語法 | 手動處理 | extends / super |
| 理解成本 | 高 | 低 |
| 本質 | prototype chain | prototype chain(包裝) |
注意事項
在實際專案中,大多數情況直接用 class 就可以;只有在寫底層 library,或真的需要精細控制 prototype 時,才需要使用 prototype。
使用 extends 來建立繼承關係,並透過 super() 呼叫父類別的 constructor:
js1class Employee extends Person { 2 constructor(name, age, jobTitle) { 3 super(name, age); 4 this.jobTitle = jobTitle; 5 } 6 7 work() { 8 console.log(`${this.name} is working as a ${this.jobTitle}.`); 9 } 10}
注意事項
super() 必須在子類別 constructor 中最先呼叫super.method() 使用JavaScript class 提供了 static 方法與 getter / setter ,但若設計不當,也容易讓 class 變得難以理解。
static 方法屬於 class 本身,而不是某一個 instance,適合用於:
js1class MathUtil { 2 static add(a, b) { 3 return a + b; 4 } 5} 6 7MathUtil.add(2, 3); // 5
注意事項
this 狀態,優先考慮使用 staticgetter / setter 讓我們可以在不改變使用方式的情況下,控制資料的存取行為。
js1class Car { 2 constructor(brand) { 3 this._brand = brand; 4 } 5 6 get brand() { 7 return this._brand; 8 } 9 10 set brand(value) { 11 if (!value) { 12 throw new Error("Brand is required"); 13 } 14 this._brand = value; 15 } 16} 17 18const car = new Car("Toyota"); 19console.log(car.brand); // Toyota 20car.brand = "Honda";
為什麼不用 public property?
注意事項
確保整個應用中只存在一個實例,常見於 logger、config manager。
js1class ConfigService { 2 static instance; 3 4 constructor() { 5 if (ConfigService.instance) { 6 return ConfigService.instance; 7 } 8 this.config = {}; 9 ConfigService.instance = this; 10 } 11} 12 13const service1 = new ConfigService(); 14const service2 = new ConfigService(); 15console.log(service1 === service2); // true
根據不同條件,產生不同類型的物件。
js1class Dog { 2 speak() { 3 return "Woof"; 4 } 5} 6 7class Cat { 8 speak() { 9 return "Meow"; 10 } 11} 12 13class AnimalFactory { 14 static create(type) { 15 switch (type) { 16 case "dog": 17 return new Dog(); 18 case "cat": 19 return new Cat(); 20 default: 21 throw new Error("Unknown animal type"); 22 } 23 } 24}
在大型系統中,組合(composition)通常比繼承更安全。
js1class Logger { 2 log(message) { 3 console.log(message); 4 } 5} 6 7class UserService { 8 constructor(logger) { 9 this.logger = logger; 10 } 11}
Class 的 constructor 很容易成為 bug 溫床,尤其在參數不可信時,所以盡量要加上 error handling。
js1class User { 2 constructor(email) { 3 if (!email) { 4 throw new Error("Email is required"); 5 } 6 this.email = email; 7 } 8}
設計準則
JavaScript class 並不是新的語言核心,而是讓 prototype 更容易被正確使用的工具。在中大型專案中,搭配良好的分層設計、適度的設計模式,class 可以有效提升可讀性、可維護性與團隊協作效率。