关于Generator函数,说实话还是不彻底的明白其意义以及相应的某些应用场景,在此只是针对目前个人境界理解程度,对其进行一次重新的记录。
一、基本概念
关于Generator函数,我就利用ES6此书上的比喻来形容。
Generator它是一个状态机,其内部封装了很多很多待处理的状态(yiled code...
【待处理状态之一】),它有三个功能键,分别是.next()
【开始处理下一个待处理状态】、.return()
【直接return结束整个状态处理操作】、.throw()
【抛出异常】。
对于Generator函数执行.next()方法时,会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束【false未遍历完毕,true已遍历完毕】。
注意:Generator返回的是个遍历器对对象Iterator,而不是构造函数,所以不可直接通过new来创建所对应的Generator实例来。
二、yield表达式
1、它本身只是个暂停标识关键字,所以单独得yiled会返回undefined,若其后存在暂缓操作code,则其返回值为其后code的返回值。
2、yield只适用于Generator函数,简单来说,只能在Generator函数中使用,其他使用场景报错。
3、在Generator函数中,当其他表达式需要使用yield时,必须将其和其后的表达式用圆括号包起来比如:console.log('Hello' + (yield 123))
,不然报错。
三、与Iterator接口的关系
1、构造对象自定义Iterator接口,因为上述基本概念得知,Generator函数返回的是一个Iterator遍历器对象,所以我们可以将其与Symbol.iterator配合从而构造对象自定义Iterator接口(遍历器)。比如:
const obj = new Proxy({
'first': 'first',
'second': 'second',
'third': undefined,
}, {
get: (target, property) => target[property] === undefined ? "暂无数据" : target[property],
})
// 布置自定义Iterator接口
Reflect.set(obj, Symbol.iterator, function* () {
for (const key in this) { // this指代数据源obj,还可以这么玩,有意思
yield this[key]
}
})
console.log([...obj]) // ["first", "second", "暂无数据"]
四、Generator与for…of循环
首先我们都知道for...of
是部署有Iterator
接口的数据结构专属特性,那么为什么for...of
只是针对存在Iterator
接口的数据结构体有作用呢?
首先得要说明一点,for...of
针对的不是部署有Iterator
接口的数据结构,而是Iterator
接口本身,也就是遍历器对象。证明如下:
const test = function* () { // 执行 Generator 函数会返回一个遍历器对象
yield 1
yield 2
yield 3
return 4
}
for (const item of test()) {
console.log(item) // 1, 2, 3
}
那为什么没有打印 4 呢?
首先我们得了解,当我们使用for...of
时,它会自动寻找实例中的遍历器对象,从而自动遍历实例对象,而不需要.next()
一步一步手动执行。
ok,这是了解for...of
循环的前提,现在我么来说说它是以什么来判断遍历的结束。我们得知道每个遍历器对象.next()
返回值是什么?
const test = function* () {
yield 1
yield 2
yield 3
return 4
}
const Test = test()
console.log(Test.next()) // {value: 1, done: false}
console.log(Test.next()) // {value: 2, done: false}
console.log(Test.next()) // {value: 3, done: false}`在这里插入代码片`
console.log(Test.next()) // {value: 4, done: true}
我们可以知道唯独没有被for..of
遍历出的 4 的相应的.next()
返回值中的done
是true,ok,那我们就可以得知.next()
方法返回的是一个包含yield
尾部语句返回值和一个标识符done
,而done
的作用则是表明实例对象是否遍历完毕,当done
为true时表示遍历完毕并且不会向for...of
返回其value值。
五、Generator三大api方法【在这里只说说.next()
的一个注意事项】
1、.next()
首先不用多说它的作用了吧,待会显得我啰嗦,哈哈哈。
注意点:.next()函数的参数是上一个yield后语句的返回值,若下一个yield依赖上一个yield就需要将值作为参数传给.next()函数。
const test = function* () {
const firstYield = yield 1
const secondYield = yield firstYield + 1
const thirdYield = yield secondYield + 1
return 4
}
const Test = test()
console.log(Test.next()) // {value: 1, done: false}
console.log(Test.next()) // {value: NaN, done: false}
console.log(Test.next()) // {value: NaN, done: false}
console.log(Test.next()) // {value: 4, done: true}
这是不加参数的结果,因为当第二个yield依赖第一个yield的结果,但是第二个.next()执行时,并不知道firstYield是个什么东西,所以返回结果为{value: NaN, done: false},下面类似道理。
const test = function* () {
const firstYield = yield 1
const secondYield = yield firstYield + 1
const thirdYield = yield secondYield + 1
return 4
}
const Test = test()
console.log(Test.next()) // {value: 1, done: false}
console.log(Test.next(1)) // {value: 2, done: false}
console.log(Test.next(2)) // {value: 3, done: false}
console.log(Test.next()) // {value: 4, done: true}
这是加了参数的结果。