JAVASCRIPT V2 · ADVANCED · 125
Higher-Order Functions / Callbacks:Function 也能成為資料與策略
你早就用過 event listener、array methods、timer 與 Promise。這些 API 的共同點是:它們接收 function,之後在特定條件下呼叫它。這一課要把「callback」從一個名詞變成可追蹤的 execution contract。
Learning outcomes
- 把 function 視為 first-class value:可指定、傳入、回傳與保存。
- 精確區分「傳 function」與「現在呼叫 function」。
- 能寫接受 callback 的 higher-order function。
- 能追蹤 callback 的 owner、input、return contract 與呼叫時機。
- 理解 array methods、events、timers 與 Promise 為何都依賴同一抽象。
1. Why now:你已經用了很多 callback,只是還沒統一理解
button.addEventListener(
"click",
handleClick
);
scores.map(
score => score * 2
);
setTimeout(
() => console.log("later"),
1000
);
三段程式看起來屬於不同領域,但都在做同一件事:把「一段之後要執行的行為」以 function value 的形式交給另一個 function。
2. Mental model:Function value 與 Function call 是兩回事
function greet(name) {
return "Hello " + name;
}
const a = greet;
const b = greet("Amy");
| binding | 保存什麼 |
|---|---|
| a | function 本身 |
| b | 呼叫 greet 後得到的 string |
看到括號時要立刻問:「這裡是在傳 function,還是在執行 function?」這是 callback bug 最常見的第一分界。
3. Worked Example A:自己寫 forEachLike
function forEachLike(
items,
action
) {
for (const item of items) {
action(item);
}
}
forEachLike(
["A", "B", "C"],
value => console.log(value)
);
forEachLike 管理 iteration;caller 注入每一輪要做的 action。這就是 higher-order function:接收或回傳 function。
4. Callback contract:不是所有 callback 都回同一種東西
students.filter(
student => student.score >= 60
);
students.map(
student => student.name
);
students.sort(
(a, b) => b.score - a.score
);
| API | callback input | callback output |
|---|---|---|
| filter | item | Boolean-like keep/drop decision |
| map | item | transformed value |
| sort | a, b | negative / zero / positive ordering signal |
5. Worked Example B:Higher-Order Function 回傳 Function
function makeMinimumScore(
minimum
) {
return function passes(
student
) {
return student.score
>= minimum;
};
}
const passes80 =
makeMinimumScore(80);
students.filter(passes80);
Higher-order 不只代表「收 callback」;回傳 function 也算。這會直接銜接下一課 closure。
6. Execution trace:callback 到底由誰呼叫?
const doubled =
[10, 20, 30].map(
n => n * 2
);
map owns iteration
round 1:
n = 10
callback returns 20
round 2:
n = 20
callback returns 40
round 3:
n = 30
callback returns 60
result:
[20, 40, 60]
關鍵不是「arrow function 很短」,而是 map 控制何時呼叫 callback、傳什麼參數、如何使用 callback return value。
7. Worked Example C:Event callback 沒有 return pipeline
button.addEventListener(
"click",
event => {
console.log(event.type);
return 123;
}
);
這裡 return 123 並不會自動變成 click event 的「結果」。不同 higher-order APIs 對 callback return value 的 contract 不同,不能把 map 的直覺套到所有 callback。
8. Common mistakes
A. 把 callback 先呼叫掉
setTimeout(
console.log("later"),
1000
);
console.log 現在就執行,傳給 setTimeout 的是 undefined。
B. 以為 callback 永遠同步
map callback 通常同步逐項跑;timer/event/Promise callback 則由排程決定。
C. 忽略 callback contract
filter callback 忘記 return Boolean-like value,可能得到空結果或錯誤結果。
D. 為了「函數式」把所有邏輯塞進一行
Higher-order abstraction 的目標是責任清楚,不是 code golf。
9. Debug evidence:四個固定問題
Callback:
1. Who stores it?
2. Who calls it?
3. When is it called?
4. What input/output contract?
如果 callback「沒有跑」,先找註冊證據;如果「跑了但資料錯」,看實際 input;如果「結果沒被採用」,檢查 host API 是否真的會消費 return value。
10. Guided exercise:寫 filterLike
function filterLike(
items,
predicate
) {
// TODO
}
const passed =
filterLike(
students,
student =>
student.score >= 60
);
要求:不使用原生 filter。每輪呼叫 predicate;只有 predicate 回傳 truthy 時把 item 放進新 array;不得修改原 array。
11. Independent exercise:排序策略注入
建立 sortStudents(students, compare),讓 caller 可以傳入「分數高到低」「姓名 A→Z」兩種 comparator。函式必須保留原陣列。
const byScore =
(a, b) => b.score - a.score;
const byName =
(a, b) =>
a.name.localeCompare(b.name);12. Challenge:回傳 validator function
寫 between(min,max),回傳一個接受 number 的 validator。接著建立 isValidScore = between(0,100)。下一課要解釋為什麼回傳的 function 還能存取 min/max。
Project checkpoint:Grade Tracker 可插拔策略
const filters = {
all: () => true,
passed: s => s.score >= 60,
excellent: s => s.score >= 90
};
function visibleStudents(
students,
filterName
) {
const predicate =
filters[filterName];
return students.filter(
predicate
);
}
Project 從「硬編碼 if」進化成行為策略 table;UI 只選策略名稱,不必知道 predicate 細節。
13. Vocabulary / Summary
- first-class function:function 可像其他 value 一樣被傳遞。
- callback:交給另一段程式、由對方在特定時機呼叫的 function。
- higher-order function:接收或回傳 function 的 function。
- predicate:通常回 Boolean-like decision 的 callback。
- comparator:比較兩個值並回 ordering signal 的 callback。
14. Further reading
Knowledge check · Mastery
- 解釋
handleClick與handleClick()的差異。 - 從 map/filter/sort 各說明 callback contract。
- 完成
filterLike與可插拔排序器。 - 在頁面下方 Executable JS practice 中先 prediction 再執行。