这是我参与更文挑战的第9天,活动详情查看:更文挑战
[重学JavaScript系列文章连载中...]
Generator()
函数是ES6的另一种异步编程解决方案。从语法上可以把它理解为一种状态机,内部维护了多个状态,函数执行后会返回一个拥有Iterator
接口的对象,通过这个对象可以依次获取Generator()
函数内部的每一个状态。
简单用法如下:
function* generator(){
yield 'one'
yield 'two'
}
let g = generator() // 获取拥有Iterator接口的对象
g.next() // 输出: {value: "one", done: false}
g.next() // 输出: {value: "two", done: false}
g.next() // 输出: {value: undefined, done: true}
从例子可以看出,Generator()函数的特性:
- function关键字和函数名之间有一个星号("*")
- 内部使用yield关键字来定义内部不同的状态
- Generator()函数不是构造函数,默认情况下不能使用new关键字,否则会报错,且内部的this也是无效的。
- Generator()函数执行后,函数体并没有直接执行,而是返回一个拥有Iterator接口的对象
- 调用next()函数才执行Generator()函数的函数体,遇到yield关键字暂停,当然若遇到return语句,则整个函数执行结束,后面的yield语句也都失效。
- next()函数返回的是一个含有value和done属性的对象,value表示的是yield表达式执行的结果
- 所有yield语句执行完毕时,函数会执行到末尾,如果有return语句,会将return语句的表达式作为value返回,否则返回undefined,同时done为true,表示遍历结束。
再来看个例子:
function* generator(){
yield 'one'
yield 'two'
return 'three'
}
let p = generator()
for(let key of p){
console.log(key) // 先后输出 one two
}
Generator()
函数返回的是一个拥有Iterator接口的对象,因此可以用for...of进行遍历,遍历的结果是yield表达式的返回值。
如何让对象类型的值遍历支持for...of呢?通过Generator()
函数,看例子:
function* propGenerator(){
let props = Object.keys(this)
for(let p of props){
// 通过yield控制每轮返回的值为属性名和属性值构成的数组
yield [p,this[p]]
}
}
let obj = {
a:1,
b:2
}
obj[Symbol.iterator] = propGenerator
for(let [p,v] of obj){
console.log(p+':'+v) // 依次输出: a:1 b:2
}
最后,看看Generator()
函数嵌套的问题,可以采用yield* 表达式以支持嵌套使用,看例子:
function* f1(){
yield '1'
}
function* f2(){
yield '2',
yield* f1()
yield '3'
}
let f = f2()
for(let k of f){
console.log(k) // 依次输出:2 1 3
}
至此,我们学习了ES6中异步编程的另一个解决方案:Generator()
函数。