Generator
函数是一个状态机,封装了多个内部状态。同时Generator
还是一个遍历器对象生成函数,执行Generator
函数会返回一个遍历器对象,返回的遍历器对象可以依次遍历Generator
函数内部的每一个状态。其特征如下:
-
function
关键字与函数名之间有一个星号 - 函数体内部使用
yield
表达式,定义不同的内部状态
function* helloWorld() {
yield 'hello'
yield 'world'
return 'ending'
}
var hw = helloWorld()
hw.next()
// {value: "hello", done: false}
hw.next()
// {value: "world", done: false}
hw.next()
// {value: "ending", done: true}
hw.next()
// {value: undefined, done: true}
调用Generator
函数后,返回的是一个指向内部状态的指针对象。调用遍历器对象的next
方法,使得指针下移一个状态,内部指针从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield
表达式。
遍历器对象的 next 方法运行逻辑:
- 遇到
yield
语句暂停执行后面的操作,并将紧跟在yield
后面的表达式的值作为返回的对象的value
属性值 - 下一次调用
next
方法时再继续往下执行,直到遇到下一条yield
语句 - 如果没有再遇到新的
yield
语句,一直运行到函数结束,直到return
语句为止,并将return
语句后面的表达式的值作为返回对象的value
属性值 - 如果该函数没有
return
语句,返回对象的value
属性值为undefined
yield 语句本身没有返回值,next 方法可以带有一个参数,该参数会被当作上一条 yield 语句的返回值
function * foo(x) {
var y = 2 * ( yield (x + 1) )
var z = yield (y / 3)
return (x + y + z)
}
// yield 语句的值就是调用 next 方法的返回值
var a = foo(5)
a.next() // 6
a.next() // NaN :------ next 方法不带参数, y 的值为 2 * undefined
a.next() // NaN
var b = foo(5) // 如果调用方法传入 next 值, next 传入的值会被当作上一条 yield 语句的返回值
b.next() // 6 ------- y: 12
b.next(12) // 8 ------y: 24, z: 4
b.next(13) // x: 5; y: 24; z: 13 ------- 42
对象的Symbol.interator
方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象,由于Generator
函数就是遍历器生成函数,可以把Generator
函数赋给Symbol.iterator
属性,从而使得该对象具有Interator
接口。
var iter = {};
iter[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...iter]
for...of 循环可以自动遍历 Generator 函数生成的 Iterator 对象,不再需要调用 next 方法。当 next 方法返回的对象的 done 属性为 true 时,for...of 循环会终止,且不包含该返回对象,return 语句返回值不会出现在 for...of 循环中
对象不具备原生 Iterator 接口,可以自行定义实现
let jane = {
first: 'Jane',
last: 'Doe'
}
function * objEnt() {
let propKeys = Object.keys(this)
for(let key of propKeys) {
yield [key, this[key]]
}
}
jane[Symbol.iterator] = objEnt
for(let [key, value] of jane) {
console.log(`${key}: ${value}`)
}
for...of 循环,扩展运算符,解构赋值和Array.from 方法内部调用的都是遍历器接口,可以将 Generator 函数返回的 Iterator 对象作为参数
网友评论