生成器(函数)是一种特殊的函数,在生成器的函数块内可以暂停和恢复代码的执行。
主要参考资料:
- 《JavaScript 高级程序设计(第4版)》- P192(217/931)
定义生成器
在使用关键字 function 定义函数对象时,通过在关键字 function 后面添加星号 *
来定义生成器。
不能使用箭头函数定义生成器。
星号 *
不受其两侧的空格影响。
示例:
// 定义生成器
function *generator() {}
function * generator01() {}
function* generator02() {}
let generator03 = function *() {}
// 在对象字面量中简写函数时
let obj = {
*generator04() {}
}
创建生成器对象
调用生成器并不会执行生成器中的代码,而是会创建一个生成器对象。
示例:
function *generator() {
return 'finished'
}
// 创建生成器对象
let generatorObj = generator()
生成器对象是迭代器。生成器对象实现了接口 Iterator ,拥有方法 next() 。但生成器对象的方法 next() 并不是用于迭代可迭代对象的。
生成器对象是可迭代对象。生成器对象也实现了接口 Iterable ,而且生成器对象的默认迭代器函数返回生成器对象自身。
执行生成器
想要执行生成器中的代码,必须调用对应的生成器对象的方法 next() 。
生成器对象拥有方法 next() ,用于使生成器进入或恢复执行状态。
【有待补充】
生成器对象的方法 next() :
- 返回值:
对象,结构为生成器结果:- 属性 done ,布尔值,表示生成器是否已经执行完毕。
- 属性 value ,生成器的返回值。
示例:
function *generator() {
return 'finished'
}
let generatorObj = generator()
// 执行生成器
console.log(generatorObj.next()) // { done: true, value: 'finished' }
生成器会对每个生成器对象执行生成器的行为区分作用域。
每个生成器对象的生成器执行是独立的,多个生成器对象之间的执行生成器的行为不会相互影响。
中断生成器
在生成器中使用关键字 yield 来指定生成器中断执行的位置。
生成器执行的中断、恢复:
- 生成器在执行时遇到关键字 yield ,会停止执行,函数作用域的状态会被保留。
- 当生成器的生成器对象调用方法 next() 时,生成器会从停止执行的位置开始恢复执行,直到遇到关键字 yield 或 return ,生成器才会停止执行。
关键字 yield 像关键字 return 一样可以返回值。
关键字 yield 只能在生成器的函数块中使用,不能在普通函数的函数块中使用。
示例:
function *generator() {
yield '01' // 中断执行,并返回值
yield '02'
return 'finished'
}
let generatorObj = generator()
console.log(generatorObj.next())
console.log(generatorObj.next())
console.log(generatorObj.next())
// 输出:
// { done: false, value: '01' }
// { done: false, value: '02' }
// { done: true, value: 'finished' }
提前终止生成器
通过调用生成器对象的方法 return() ,提前终止生成器。
生成器对象的方法 return() 会强制生成器进入关闭状态。
生成器对象的方法 return() :
-
功能:
强制生成器进入关闭状态。 -
接收一个参数:
任意值,用作返回值对象的属性 value 的值。 -
返回值:
对象,结构为生成器结果:- 属性 done ,值为 true ,表示生成器终止执行(执行完毕)。
- 属性 value ,方法接收的第一个参数。
示例:
function *generator() {
yield '01'
yield '02'
return 'finished'
}
let generatorObj = generator()
console.log(generatorObj.next())
console.log(generatorObj.return('Exiting early')) // 提前终止生成器
console.log(generatorObj.next())
// 输出:
// { done: false, value: '01' }
// { done: true, value: 'Exiting early' }
// { done: true, value: undefined }
向生成器抛出错误
通过调用生成器对象的方法 throw() ,向生成器抛出错误。
生成器对象的方法 throw() 会恢复生成器的执行,直到遇到关键字 yield 或 return ,生成器才会停止执行。
生成器对象的方法 throw() :
-
功能:
向生成器抛出错误。 -
接收一个参数:
任意值,错误信息。 -
返回值:
对象,结构为生成器结果:- 属性 done ,布尔值,表示生成器是否终止执行(执行完毕)。
- 属性 value ,生成器的返回值。
生成器处理生成器对象抛出的错误:
- 如果生成器没有处理生成器对象抛出的错误,生成器就会关闭。
- 如果生成器处理了生成器对象抛出的错误,生成器继续正常执行。
示例:
-
向生成器抛出错误
function *generator() { yield '01' yield '02' return 'finished' } let generatorObj = generator() console.log(generatorObj.next()) try { console.log('Returned Value of throw(): ', generatorObj.throw('Error01')) // 向生成器抛出错误 } catch(e) { console.log('Error: ', e) } console.log(generatorObj.next()) // 输出: // { done: false, value: '01' } // Error: Error01 // Returned Value of throw(): { done: true, value: undefined }
-
生成器处理错误
function *generator() { try { yield '01' } catch(e) { // 捕获错误 console.log('Generator dealed error: ', e) } yield '02' return 'finished' } let generatorObj = generator() console.log(generatorObj.next()) try { console.log('Returned Value of throw(): ', generatorObj.throw('Error02')) } catch(e) { console.log('Error: ', e) } console.log(generatorObj.next()) // 输出: // { done: false, value: '01' } // Generator dealed error: Error02 // Returned Value of throw(): { done: false, value: '02' } // { done: true, value: 'finished' }
生成器对象向生成器传参
生成器对象在调用方法 next() 时,为 next() 提供参数,可以向生成器传递这个参数。
生成器的关键字 yield 会接收生成器对象传递的参数。
示例:
function *generator() {
let data = yield
console.log(data)
data = yield
console.log(data)
}
let generatorObj = generator()
// 生成器对象向生成器传参
generatorObj.next() // 启动生成器
generatorObj.next('one') // one
generatorObj.next('two') // two
【补充】
生成器对象的方法 next() :
-
功能:
用于使生成器进入或恢复执行状态,并向生成器传参。 -
接收一个参数:
任意值,被生成器的关键字 yield 接收。 -
返回值:
对象,结构为生成器结果:- 属性 done ,布尔值,表示生成器是否已经执行完毕。
- 属性 value ,生成器的返回值。
自动迭代生成器对象
生成器对象是可迭代对象,可以对生成器对象使用自动迭代。
示例:
function *generator() {
yield '01'
yield '02'
return 'finished'
}
let generatorObj = generator()
// 自动迭代生成器对象
for(const item of generatorObj) {
console.log(item)
}
// 输出:
// 01
// 02
生成器迭代可迭代对象
生成器通过在关键字 yield 和可迭代对象之间添加星号 *
,来迭代一个可迭代对象。
星号 *
不受其两侧的空格影响。
生成器迭代可迭代对象的主要过程:
- 创建可迭代对象的迭代器。
- 调用迭代器的方法 next() 。
- 判断迭代器结果的属性 done 。
- 如果迭代器结果的属性 done为 false ,则使用关键字 yield 返回迭代器结果的属性 value 的值。并转到过程 2 。
- 如果迭代器结果的属性 done为 true,则获取迭代器结果的属性 value 的值。
- 结束。
因此生成器会将可迭代对象的迭代器最终返回的迭代器结果 { done: true, value: any }
的属性 value 的值作为 yield* 最终的值,但不会停止执行来返回 yield* 的值。
示例:
function *generator() {
yield* [1, 2] // 迭代可迭代对象
return 'finished'
}
let generatorObj = generator()
console.log(generatorObj.next().value)
console.log(generatorObj.next().value)
console.log(generatorObj.next().value)
// 输出:
// 1
// 2
// finished
function *generator01() {
console.log('yield*: ', yield* [1, 2])
return 'finished'
}
generatorObj = generator01()
console.log(generatorObj.next().value)
console.log(generatorObj.next().value)
console.log(generatorObj.next().value)
// 输出:
// 1
// 2
// yield*: undefined
// finished