在 JavaScript 中,生成器函數 Generator Function?是一種特殊的函數,它允許你在函數執行過程中暫停和恢復。生成器函數通過 function* 語法定義,并使用 yield 關鍵字來控制函數的執行流程。生成器函數返回一個生成器對象,該對象遵循迭代器協議,可以逐步生成值。
以下是生成器函數的詳細解析:
1. 基本語法
生成器函數使用 function* 定義,函數體內可以使用 yield 關鍵字來暫停函數的執行并返回一個值。
function* myGenerator() {yield 1;yield 2;yield 3;
}
function*:定義生成器函數的關鍵字。
yield:暫停函數執行并返回一個值。每次調用生成器對象的 next() 方法時,函數會從上次暫停的地方繼續執行。
2. 生成器對象
生成器函數調用時不會立即執行函數體,而是返回一個生成器對象。這個生成器對象是一個迭代器,可以通過?next()?方法逐步執行生成器函數。
const gen = myGenerator();console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
next():恢復生成器函數的執行,直到遇到下一個?yield?或函數結束。
返回一個對象,包含兩個屬性:
value:yield?表達式的值。
done:布爾值,表示生成器函數是否已經執行完畢。
3. yield?關鍵字
yield 是生成器函數的核心關鍵字,它的作用如下:
1. 暫停函數執行:當生成器函數執行到 yield 時,會暫停執行并返回 yield 后面的值;
2. 恢復函數執行:當調用生成器對象的 next() 方法時,函數會從上次暫停的地方繼續執行,直到遇到下一個 yield 或函數結束;
function* myGenerator() {yield "Hello";yield "World";
}const gen = myGenerator();console.log(gen.next().value); // 'Hello'
console.log(gen.next().value); // 'World'
console.log(gen.next().done); // true
4.?yield*?表達式
yield* 用于委托給另一個生成器或可迭代對象(如數組、字符串等)。它允許在一個生成器函數中調用另一個生成器函數。
function* generator1() {yield 1;yield 2;
}function* generator2() {yield* generator1(); // 委托給 generator1yield 3;
}const gen = generator2();console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
console.log(gen.next().done); // true
5.?生成器函數的特性
5.1.?惰性求值
生成器函數是惰性的,只有在調用?next()?時才會執行。這使得生成器非常適合處理大量數據或無限序列。
function* infiniteSequence() {let i = 0;while (true) {yield i++;}
}const gen = infiniteSequence();console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// 可以無限調用
5.2.?雙向通信
生成器函數不僅可以通過 yield 返回值,還可以通過 next() 方法接收外部傳入的值。
function* generator() {const x = yield "Hello";yield x;
}const gen = generator();console.log(gen.next().value); // 'Hello'
console.log(gen.next(42).value); // 42
第一次調用 next() 時,生成器函數執行到 yield 'Hello' 并暫停。
第二次調用 next(42) 時,42 會作為 yield 表達式的值傳入,生成器函數繼續執行。
5.3. 提前終止
生成器對象提供了?return()?和?throw()?方法,可以提前終止生成器函數的執行。
return(value):終止生成器函數并返回指定的值。
throw(error):在生成器函數內部拋出一個錯誤。
function* generator() {yield 1;yield 2;yield 3;
}const gen = generator();console.log(gen.next().value); // 1
console.log(gen.return(42).value); // 42
console.log(gen.next().done); // true
6. 生成器函數的應用場景
6.1.?惰性求值
生成器函數非常適合處理大量數據或無限序列,因為它只在需要時生成值。
function* fibonacci() {let [prev, curr] = [0, 1];while (true) {yield curr;[prev, curr] = [curr, prev + curr];}
}const fib = fibonacci();console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
console.log(fib.next().value); // 5
6.2.?異步編程
在 async/await 出現之前,生成器函數常用于簡化異步編程。通過結合 Promise 和生成器,可以實現類似于 async/await 的效果。
function* asyncGenerator() {const result1 = yield new Promise((resolve) =>setTimeout(() => resolve(1), 1000));const result2 = yield new Promise((resolve) =>setTimeout(() => resolve(2), 1000));return result1 + result2;
}function runGenerator(generator) {const gen = generator();function handle(result) {if (result.done) return Promise.resolve(result.value);return Promise.resolve(result.value).then((res) => {return handle(gen.next(res));});}return handle(gen.next());
}runGenerator(asyncGenerator).then(console.log); // 3
6.3.?自定義迭代器
生成器函數可以用于創建自定義迭代器,簡化迭代器的實現。
const myIterable = {*[Symbol.iterator]() {yield 1;yield 2;yield 3;},
};for (const value of myIterable) {console.log(value); // 1, 2, 3
}
7. 總結
1. 生成器函數使用 function* 定義,通過 yield 暫停和恢復執行;
2. 生成器函數返回一個生成器對象,該對象是一個迭代器,可以通過 next() 方法逐步執行;
3. yield* 用于委托給另一個生成器或可迭代對象;
4. 生成器函數適用于惰性求值、異步編程和自定義迭代器等場景;
生成器函數提供了一種強大的控制流機制,使得你可以更靈活地管理函數的執行過程。