JAVASCRIPT V2 · EVERYDAY · 61
Class / Object Model:何時資料與行為值得放在同一個 Instance?
學到 class 不代表所有 object 都應該變成 class。這一課要比較三種設計:plain data + functions、factory/object、class instances。你要能說明 state、method、this、prototype 與 serialization trade-off,而不是只背 constructor。
Learning outcomes
- 區分 class、instance、instance state、method。
- 理解
this與 call-site 的基本關係。 - 知道 class methods 與 prototype model 的關係。
- 比較 class、plain object + pure functions 的 trade-offs。
- 避免不必要 inheritance hierarchy。
1. Why now:有些 entity 真的需要「每個 instance 有 state + 共享 behavior」
const courseA = {
title: "JS",
score: 90
};
const courseB = {
title: "Math",
score: 55
};
如果很多 Course 都需要相同 isPassed() behavior,class 是一種組織方式;但不是唯一方式。
2. Class / Instance / State / Method
class Course {
constructor(title, score) {
this.title = title;
this.score = score;
}
isPassed() {
return this.score >= 60;
}
}
const js =
new Course("JavaScript", 90);
| Term | Example |
|---|---|
| class | Course |
| instance | js |
| instance state | title / score |
| method | isPassed() |
3. Worked Example A:不同 instances,各自保存 state
const js =
new Course("JavaScript", 90);
const math =
new Course("Math", 55);
js.isPassed(); // true
math.isPassed(); // false
method code 是共享行為,但 this.score 讀的是目前 call receiver 的 instance state。
4. this 不是「永遠自動指 class」
const check = js.isPassed;
check();
// call-site 改變,this 不一定是 js
JavaScript 的 this 取決於呼叫方式。這一課先建立警覺,130 會深入 prototype/this。
5. Class syntax 建立在 prototype model 上
console.log(
Course.prototype.isPassed
);
一般 class method 不會每個 instance 都複製一份 function;它們透過 prototype mechanism 共享。現在不需要背 prototype chain 細節,但要知道 class 不是獨立於 JavaScript object model 的另一套世界。
6. Plain object + pure function 仍然很強
const student = {
name: "Amy",
score: 92
};
function isPassed(student) {
return student.score >= 60;
}
API payload、DTO、configuration 等資料常常用 plain object 更直接,也更容易 JSON serialize。
7. Worked Example B:同一需求的兩種設計
// Data + function
const course = {
title: "JS",
score: 90
};
isPassed(course);
// Class
const course2 =
new Course("JS", 90);
course2.isPassed();
沒有「class 比 object 高級」。選擇取決於 behavior/invariant 是否真的和 instance identity 綁得很緊。
8. Constructor 可以建立 invariant,但不要藏太多 side effects
class Course {
constructor(title, score) {
if (!title) {
throw new Error("title required");
}
this.title = title;
this.score = score;
}
}
Constructor 適合建立有效初始 state;不宜隨便塞 network request、DOM 操作等難以預期的 side effects。
9. Serialization boundary:JSON 不會保存 method behavior
const raw =
JSON.stringify(
new Course("JS", 90)
);
const restored =
JSON.parse(raw);
restored 只有 data properties,不會自動恢復成 Course instance/method。這就是 object model 與 transport representation 的 boundary。
10. Inheritance 不是 class 的必修終點
Entity
→ Person
→ Student
→ OnlineStudent
→ PremiumOnlineStudent
過深 inheritance 會把 behavior 耦合在 hierarchy。很多情況 composition + plain functions 更清楚。
11. Worked Example C:Composition
function createCourse(
data,
gradingPolicy
) {
return {
...data,
isPassed() {
return gradingPolicy(
this.score
);
}
};
}
這不是要求你改用 factory;只是要看到「共享 behavior」不只 inheritance 一種解法。
12. Common mistakes
A. 所有 API data 都轉 class
增加 mapping/serialization 成本,未必有價值。
B. method extraction 後以為 this 仍自動綁 instance
call-site 會影響 this。
C. constructor 做太多 I/O
建立 object 變得難測、難預期。
D. 用 inheritance 表達其實只是「有某個能力」
composition 往往更靈活。
13. Debug evidence:確認 instance / prototype / call-site
console.log(
js instanceof Course
);
console.log(
Object.getPrototypeOf(js)
=== Course.prototype
);
如果 method 行為怪異,也要看它是怎麼被呼叫,而不是只看 method 定義。
14. Guided exercise:兩個 instances
const a =
new Course("A", 60);
const b =
new Course("B", 59);
預測 a/b 的 isPassed(),再說明 this.score 每次讀的是哪個 state。
15. Independent exercise:實作 Course.summary()
Course 有 title/score;isPassed() 判斷 60;summary() 回傳 JS:Pass 或 Math:Fail。多個 instances 都要成立。
16. Challenge:選設計並寫理由
三種資料:API response DTO、DOM button component state、bank account domain entity。哪些適合 plain object + pure function,哪些可能值得 class?理由必須談 behavior/invariant/serialization,而不是「class 比較專業」。
Project checkpoint:Grade Tracker Design Decision
容易 JSON / storage / testing;適合 Grade Tracker 現有資料流。
若 Course 有長期 instance behavior/invariant,class 可能更自然。
目前 Grade Tracker 預設仍採 plain Student objects + pure functions,因為資料需要頻繁 serialize、filter、map。Class 只作為可理解的設計選項,不強制套用。
17. Vocabulary / Summary
- class:建立 instances 的語法/模型。
- instance:某個具體 object。
- method:與 object/class 行為相關的 function。
- this:由 call-site 決定的 receiver context。
- prototype:JavaScript object behavior sharing 的核心機制。
- composition:用組合能力取代過深 inheritance。
18. Further reading
Knowledge check
- 區分 class、instance、state、method。
- 說明 method extraction 為何可能影響 this。
- 解釋 JSON round trip 為何不會保存 class methods。
- 比較 plain object + pure function 與 class 的 trade-off。
- 完成 Course.summary() mastery tests。