在當代 JavaScript 開發中,我們熟悉了箭頭函式、解構賦值與模板字串等語法糖,但「生成器函式」卻總被視為語法中的冷門角色。不過,它其實具備強大潛力,特別是在控制流程、延遲求值與封裝狀態管理方面,是現代前端工程師的低調救星。
透過這篇文章,我們將系統性解析 Generator(產生器)函式的 特性、原理 與 實戰應用模式,幫助你從基礎到進階,掌握這項語法的實用價值。
基礎概念
1.迭代器與可迭代物件(Iterator / Iterable)
- 定義
next()
的物件即為迭代器。 - 實作
Symbol.iterator()
的物件為可迭代物件。
const gospelIterator = {
index: -1,
next() {
const gospels = ["Matthew", "Mark", "Luke", "John"];
this.index++;
return {
value: gospels.at(this.index),
done: this.index + 1 > gospels.length,
};
},
};
2.Generator 作為迭代器工廠
function* generateAlphabet() {
for (let i = 97; i <= 122; i++) {
yield String.fromCharCode(i);
}
}
語法特性總覽
function*
定義生成器。yield
暫停與傳值。yield*
委派子生成器或其他可迭代物件。
執行機制解析:Generator 如何「延遲」與「記憶」
1.Lazy Evaluation(延遲求值)
- 每次執行
next()
時才計算。 - 可用於大量資料或昂貴運算。
function* infiniteCounter() {
let i = 0;
while (true) yield i++;
}
2.狀態保留
- 每次
yield
暫停執行,並保留上下文。
3.控制流程 API
next(value)
:傳值並繼續。return(value)
:提前結束。throw(err)
:拋出錯誤中斷。
Generator 應用場景:寫出更清晰的程式邏輯
自訂迭代器:產生器模式的應用
function* idGenerator() {
let id = 1;
while (true) yield id++;
}
移動平均數(狀態機應用)
function* calculateMovingAverage(values, windowSize) {
let start = 0;
while (start <= values.length - windowSize) {
yield values.slice(start, start + windowSize)
.reduce((a, b) => a + b, 0) / windowSize;
start++;
}
}
分頁資料流(資料物件延遲產生)
async function* fetchAllPages() {
let page = 1;
while (true) {
const res = await apiRequest(page++);
if (!res.hasMore) return;
yield res.items;
}
}
非同步資料輪詢(Async Generator)
async function* monitorVitals() {
while (true) {
yield await requestVitals();
await delay(1000);
}
}
控制反轉(Inversion of Control)
for (const value of generator) {
await new Promise(r => {
button.addEventListener("click", () => {
render(value);
r();
}, { once: true });
});
}
進階技巧與模式應用
錯誤處理與 try-catch 配合
function* g() {
try {
yield 1;
yield 2;
} catch (e) {
console.log("Caught:", e);
}
}
yield*
委派機制
function* sub() {
yield 'a';
yield 'b';
}
function* main() {
yield* sub();
yield 'c';
}
實戰應用:DOM 元素批次產生
function* getElements(tagName) {
while (true) yield document.createElement(tagName);
}
const [div1, div2] = getElements('div');
Generator 提供一種清晰、延遲、可控的資料生產流程。
適合處理狀態儲存、資料流、非同步控制與大型迭代物件。