1.Generator介绍
声明:Generator函数是ES6提供的一种异步编程的解决方案,可以看成一个状态机,封装了多个内部状态,执行Generator函数会返回一个遍历器对象,所以也是遍历器对象生成函数。 Generator函数也是一个普通函数,但是有两个特征。第一是funtction关键字与函数名之间有个*,第二是函数体内部使用yield表达式,定义不同的内部状态。
function* fun() {
yield "张三" //状态1
yield "李四" //状态2
return "结束" //状态3
}
const obj = fun()
console.log(obj); //fun {<suspended>}
声明: 返回的是一个指向内部状态的指针对象,也就是遍历器对象。
2.Generator 函数是分段执行
声明:Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
console.log(obj.next()); //{value: '张三', done: false}
console.log(obj.next()); //{value: '李四', done: false}
console.log(obj.next()); //{value: '结束', done: true}
// 第三次调用Generator函数从上次yield表达式停下的地方,一直执行到下一个yield表达式。如果有retrun就执行到retrun
console.log(obj.next()); //{value: undefined, done: true}
3. yield表达式
声明:一种可以暂停函数的标志的表达式,只有调用next()方法,内部指针指向该语句才执行。我们可以看成一种惰性求值的语法功能。
function* fun2(a, b) {
yield a + b
return a * 5
}
const obj2 = fun2(5, 6)
console.log(obj2); //fun2 {<suspended>}
console.log(obj2.next()); //{value: 11, done: false}
console.log(obj2.next()); //{value: 25, done: true}
console.log(obj2.return(5)); //{value: 5, done: true}
注意:return与yield区别,一个函数里面只能有一个return语句。
4.特殊形式
说明:Genrator函数可以不用yield表达式,这时就变成了一个单纯的暂缓执行函数。
function* fun3() {
console.log("Hello world");
}
console.log(fun3().next());
//Hello world
//{value: undefined, done: true}
5.yield表达注意点
- yield表达式,只能在Generator函数里面。
- yield表达式如果用在另一个表达式之中,必须放在圆括号里。
function* fun4() {
console.log("你好" + (yield 123));
console.log("你好" + (yield 234));
}
const obj4 = fun4()
console.log(obj4.next()); //{value: 123, done: false}
console.log(obj4.next()); //{value: 234, done: false}
6.与Iterator接口的关系
说明:由于Generator函数就是遍历器生成函数,因此可以把Geneartor赋值给等下给对象的Symbol.iterator属性,从而使得该对象具有Iterator接口。
const myIter = {}
myIter[Symbol.iterator] = function* fun5() {
yield 1
yield 2
return 3
}
console.log(...myIter);
//1 2
说明:没有3这个结果,说明只会遍历yield声明的表达式。(是因为返回对象的done属性为true,for...of循环就会中止)
7.Generator函数时遍历器函数
const fun6 = function* () {
}
const newFun6 = fun6()
console.log(newFun6 === newFun6[Symbol.iterator]()); //true
8. next方法的参数
说明:next方法可以带一个参数,该参数就会当成一个yield表达式的返回值。
function* fun7(x) {
let a = 4 * (yield (x + 1))
let b = yield (a / 3)
return (a + b + x)
}
const obj5 = fun7(1)
console.log(obj5.next()); //{value: 2, done: false}
console.log(obj5.next()); //{value: NaN, done: false}
console.log(obj5.next()); //{value: NaN, done: true}
// 第二次运行next()方法的时候不带参数,导致4*undefined等于NaN
const obj6 = fun7(2)
console.log(obj6.next()); //{value: 3, done: false}
console.log(obj6.next(2)); //{value: 2.6666666666666665, done: false}
console.log(obj6.next(3)); //{value: 13, done: true}
说明:next方法的参数表示上一个yield表达式的返回值,所以在第一次使用next方法,是不需要参数的。v8引擎直接忽略第一个使用的next()方法,只有第二次使用next()方法开始,参数还是有效的。
9.for ...of 循环
说明:for...of循环可以自动遍历Genrator函数运行时生成的Iterator对象,且此时不再需要调用next()方法。
function* fun8() {
yield 1
yield 2
yield 3
return 4
}
for (let i of fun8()) {
console.log(i);
//1
//2
//3
}
注意:不遍历return是因为返回对象的done属性为true,for...of循环就会中止,且不包含该返回对象。
10.Generator.prototype.throw
说明:Generator函数返回的遍历器对象,可以有throw方法,可以在函数Generartor函数体内捕获。
const fun9 = function* () {
try {
yield
} catch (error) {
console.log("内部捕获", error);
}
}
const obj8 = fun9()
obj8.next()
try {
obj8.throw("错误1")
obj8.throw("错误2")
} catch (error) {
console.log("外部捕获", error);
}
//内部捕获 错误1
//外部捕获 错误2
说明:由于Generator函数内部的catch语句已经执行过了,就不会捕获到这个错误了,然后抛出了Generator函数体。
11.Genrator.prototype.return
说明:Generator 函数返回的遍历器函数,还有一个return方法,可以返回指定值,并终结Generator函数。
function* fun10() {
yield 1
yield 2
}
const obj10 = fun10()
console.log(obj10.next()); //{value: 1, done: false}
console.log(obj10.return(10));//{value: 10, done: true}
console.log(obj10.next()); //{value: undefined, done: true}
12.try...finally
说明:使用try...finally代码块,且正在执行try代码块那么return()方法会导致立刻进入finally代码块,执行完,整个函数才会结束。
function* fun11() {
try {
yield 1
yield 2
} finally {
yield 10
yield 20
}
}
const obj11 = fun11()
console.log(obj11.next()); //1
console.log(obj11.return(10)); //{value: 10, done: false}
console.log(obj11.next()); //{value: 20, done: false}
13. next(),throw(),return()共同点
说明:其实作用时Generator函数恢复执行,并且使用不同语句替换yield表达式。
14.yield*表达式
说明: 解决Generator函数里面执行另一个Generator函数。
function* fun12() {
yield 2
yield 3
}
function* fun13() {
yield 4
yield* fun12()
yield 5
}
// 等价于
function* fun13() {
yield 4
yield 2
yield 3
yield 5
}
15.对象属性的Generator函数
说明:如果对象的属性时Generator函数,可以简写成下面的形式。
const obj12 = {
*fun14() {
}
}
16.Generator函数的this
说明:因为Generator函数总是返回一个遍历器,它就是Generator函数的实例。要改变可以通过call方法,apply方法等修改this的指向。
function* fun15() {
this.a = 666
yield 1
}
const obj14 = {
}
const obj15 = fun15()
obj15.next()
console.log(obj15.a); //undefined
// 改变this
const obj16 = fun15.call(obj14)
console.log(obj16.next());//{value: 1, done: false}
console.log(obj14.a);
注意:构造函数调用以后,这个空对象就是 Generator 函数的实例对象了。