?一、迭代器(Iterator):數據遍歷的統一協議 ?
1. 迭代器協議的本質
**迭代器協議(Iterator Protocol)** 是一種標準化的數據訪問接口,它要求對象實現一個 `next()` 方法,每次調用返回包含 `{ value, done }` 的對象。 ?
- **`value`**: 當前遍歷的值 ?
- **`done`**: 布爾值,表示遍歷是否結束 ?
const arrayIterator = {data: [1, 2, 3],index: 0,next() {return this.index < this.data.length?? { value: this.data[this.index++], done: false }: { value: undefined, done: true };}
};console.log(arrayIterator.next()); // { value: 1, done: false }
此迭代器通過內部維護的 `index` 狀態,逐步遍歷數組元素。
?2. 可迭代對象(Iterable) ?
若對象實現了[Symbol.iterator]()?方法,則稱為 可迭代對象。該方法返回一個迭代器,使得對象可被 `for...of` 等語法消費。
自定義可迭代鏈表:??
class LinkedList {constructor() {this.nodes = [];}add(node) {this.nodes.push(node);}[Symbol.iterator]() {let index = 0;return {next: () => ({value: this.nodes[index++],done: index > this.nodes.length})};}
}const list = new LinkedList();
list.add('a'); list.add('b');
for (const node of list) {console.log(node); // 'a', 'b'
}
?二、生成器(Generator):迭代器的超級語法糖 ?
1. 生成器的核心機制
生成器函數(function*)返回一個 生成器對象,該對象既是迭代器,也是可迭代對象。其核心能力在于: ?
- 暫停與恢復執行:通過 `yield` 關鍵字中斷函數,保留上下文狀態 ?
- 雙向通信:`yield` 可向外傳遞值,外部可通過 `next(arg)` 向內注入值 ?生成器執行流程 ?
function* gen() {const a = yield 1;const b = yield a + 2;yield b * 3;
}const g = gen();
console.log(g.next()); ? ? ?// { value: 1, done: false }
console.log(g.next(10)); ? ?// { value: 12, done: false } (a = 10)
console.log(g.next(5)); ? ? // { value: 15, done: false } (b = 5)
console.log(g.next()); ? ? ?// { value: undefined, done: true }
**關鍵點**:每次 `next(arg)` 的 `arg` 會賦值給左側 `yield` 表達式的返回值。
2. 生成器的底層模型 ?
生成器本質是 **協程(Coroutine)** 的輕量級實現。與線程不同,協程的切換由開發者顯式控制,且不涉及系統內核,因此極其高效。 ?
- 執行上下文棧:生成器暫停時,其執行上下文(變量、作用域鏈)被保存,恢復時重新壓入棧頂 ?
- 狀態機轉換:Babel 等工具將生成器轉換為帶有 `switch-case` 的狀態機代碼 ?
?三、高級應用場景 ?
1. 異步流程控制:生成器的革命性貢獻 ?
在 `async/await` 普及前,生成器 + Promise 是處理異步代碼的終極方案,其核心模式如下: ?
實現自動執行器 ?
function run(generator) {const g = generator();function handle(result) {if (result.done) return result.value;return result.value.then(data => handle(g.next(data)),err => handle(g.throw(err)));}return handle(g.next());
}run(function* fetchUser() {const user = yield fetch('/api/user');const posts = yield fetch(`/api/posts?userId=${user.id}`);return { user, posts };
}).then(data => console.log(data));
此模式直接催生了 `async/await` 的誕生,兩者在 Babel 中被編譯為類似的生成器代碼。
?2. 無限數據流與惰性計算 ?
生成器天然適合處理大規模或無限序列,僅在需要時計算值,避免內存爆炸。
斐波那契數列 ?
function* fibonacci() {let [prev, curr] = [0, 1];while (true) {yield curr;[prev, curr] = [curr, prev + curr];}
}const seq = fibonacci();
console.log(seq.next().value); // 1
console.log(seq.next().value); // 1
console.log(seq.next().value); // 2
// 可無限調用,但每次只計算一個值
3. 復雜狀態機 ?
生成器通過 `yield` 管理狀態轉移,代碼比傳統狀態機更簡潔。
?交通燈狀態機 ?
function* trafficLight() {while (true) {yield 'Red'; // 返回 'Red'yield delay(3000); // 返回 Promise,暫停 3 秒yield 'Green'; // 返回 'Green'yield delay(2000); // 返回 Promise,暫停 2 秒yield 'Yellow'; // 返回 'Yellow'yield delay(1000); // 返回 Promise,暫停 1 秒}
}function delay(ms) {return new Promise(resolve => setTimeout(resolve, ms));
}// 使用
const light = trafficLight();function runTrafficLight() {const { value, done } = light.next();if (done) return; // 如果生成器結束,退出if (typeof value === 'string') {console.log(value); // 更新 UI 為當前顏色runTrafficLight(); // 繼續下一步} else if (value instanceof Promise) {value.then(() => runTrafficLight()); // 等待 Promise 完成后再繼續}
}runTrafficLight(); // 啟動交通燈
四、生成器與迭代器的未來 ?
1. 異步迭代器(Async Iterator) ?
ES2018 引入的異步迭代器,允許迭代異步數據源(如數據庫流、WebSocket): ?
async function* asyncCounter() {let i = 0;while (i < 3) {await sleep(1000);yield i++;}
}
(async () => {for await (const num of asyncCounter()) {console.log(num); // 0, 1, 2(每秒輸出一個)}
})();
?