ES6(ECMAScript 2015)引入了生成器(Generators),這是一個(gè)非常強(qiáng)大的特性,它允許你定義一個(gè)函數(shù),這個(gè)函數(shù)可以被暫停和恢復(fù)。生成器函數(shù)返回一個(gè)迭代器對(duì)象,該對(duì)象可以在每次調(diào)用其 next() 方法時(shí)執(zhí)行到下一個(gè)yield表達(dá)式,并返回一個(gè)具有 value 和 done 屬性的對(duì)象。
Generator 的基本語法
定義一個(gè)生成器函數(shù)使用 function* 語法,或者在類的方法前加 *。在函數(shù)體內(nèi)部,你可以使用yield關(guān)鍵字來暫停執(zhí)行,并將值傳遞給調(diào)用者。
function* generatorFunction() {
yield 'Hello';
yield 'World';
return 'End';
}
const iterator = generatorFunction();
console.log(iterator.next()); // { value: 'Hello', done: false }
console.log(iterator.next()); // { value: 'World', done: false }
console.log(iterator.next()); // { value: 'End', done: true }
console.log(iterator.next()); // { value: undefined, done: true }
yield 表達(dá)式
yield 用于生成器函數(shù)中,表示函數(shù)在此處暫停,并且會(huì)返回 yield 后面的表達(dá)式的值。當(dāng)再次調(diào)用 next() 時(shí),函數(shù)會(huì)從上次暫停的地方繼續(xù)執(zhí)行,直到遇到下一個(gè) yield 或到達(dá)函數(shù)的末尾。
發(fā)送值給生成器
除了獲取生成器產(chǎn)生的值,還可以通過 next() 方法向生成器發(fā)送值。第一次調(diào)用 next() 時(shí)傳入的值會(huì)被忽略,因?yàn)闆]有 yield 表達(dá)式接收它。但是之后的 next() 調(diào)用可以將值傳遞給生成器中的 yield 表達(dá)式。
function* echoGenerator() {
while (true) {
let value = yield;
console.log(value);
}
}
const echo = echoGenerator();
echo.next(); // 啟動(dòng)生成器,首次調(diào)用next()不傳遞參數(shù)
echo.next('Hi'); // 輸出: Hi
使用for...of循環(huán)
由于生成器返回的是一個(gè)迭代器對(duì)象,因此可以直接在for...of循環(huán)中使用生成器函數(shù)。
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
for (let value of generateSequence(1, 3)) {
console.log(value); // 輸出: 1, 2, 3
}
Generator 的應(yīng)用場(chǎng)景
- 異步編程:盡管 Promises 和 async/await 是處理異步代碼的主要方式,但在某些情況下,生成器與協(xié)程庫(如co)一起使用可以簡(jiǎn)化異步流程控制。
- 數(shù)據(jù)流控制:生成器可以用來實(shí)現(xiàn)復(fù)雜的迭代模式,例如無限序列、樹遍歷等。
- 懶加載數(shù)據(jù):只在需要的時(shí)候才生成數(shù)據(jù),這對(duì)于處理大數(shù)據(jù)集特別有用。
總之,生成器提供了一種優(yōu)雅的方式來編寫可以逐步執(zhí)行并產(chǎn)生一系列值的函數(shù),這為JavaScript帶來了更豐富的編程范式。