1.含义
Generator 和普通函数不同,可以将它看成是封装了很多状态的函数,每执行一次该函数,就会返回一个遍历器对象,该遍历对象可以遍历Generator函数中的每一个状态。
2.特征
① 命名:在函数名前面加个星号
② 定义状态
使用yield表达式,每一个yield定义的表达式就是Generator函数的一个状态
③ 执行
通过普通函数调用的形式调用Generator函数,并不会执行,而是返回一个生成器对象实例,只有调用了实例中的next()方法才会执行内部的代码
④ 返回结果
并不是一个具体的数据,而是一个执行内部状态的指针对象
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next(); //{value:'hello',done:'false'}
hw.next(); //{value:'world',done:'false'}
hw.next(); //{value:'ending',done:'false'}
hw.next(); //{value:'undefined',done:'ture'}
上述代码中,共有三个状态 'hello'、'world'、'ending'。 通过函数调用的形式将helloWorldGenerator的一个生成器对象实例赋值到 hw中。然后通过hw实例的next方法执行函数内的代码,具体的执行步骤如下:
第一次调用next方法,遍历对象的指针从函数头部往下移动,开始执行函数内的代码,遇到第一个yield,暂停函数的执行,此时next()方法返回一个对象: {value:'hello',done:'false'}。value的值就是yield表达式的值,done的值为false,表示函数并没有执行完毕;
第二次调用next方法,遍历对象的指针从第一个yield表达式的地方开始往下移动,直到遇到第二个yield,停止函数的执行,同样,此时next方法也返回一个对象:{value:'world',done:'false'};
第三次调用next方法,遍历对象的指针从第二个yield表达式的大方开始往下移动,直到遇到return关键字,终止函数的执行,此时next方法也返回一个对象: {value:'ending',done:'true'};
第四次调用next方法,遍历对象的指针在第三步已经指向了该函数的结尾,表示函数已经执行完毕,此时的next方法也返回一个对象:{value:'undefined',done:'true'}.不管后面调用多少次的next方法,只要遇到了return关键字或者已经执行到函数的末尾,value值就为undefined,done值都为true。
3.yield
Generator函数相当于是分段执行的,而yield相当于一个暂停标记,只要遇到一个yield表达式,函数就会暂停执行,直到调用了next方法,当调用了next()方法,yield后面的表达式才会被执行。
function* gen() {
yield 123 + 456;
}
上述代码中,123 + 456 不会立即求值,直到调用了next()方法才会求值。
另外,yield表达式如果用在另一个表达式之中,必须放在圆括号里面。
function* gen() {
consoloe.log('hello' + yield world) //Error
consoloe.log('hello' + (yield world)) //right
}
yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号。
function* gen(a) {
gen(yield 1);
let b = yield 4;
}
4.next 执行逻辑
首先明确,执行完next()方法就不返回一个对象: {value:'',done:''}。value的值就是yield或者return 后面的值,done的值为Boolean,表示该函数是否遍历完毕,具体的执行逻辑如下:
① 首次调用next()方法,遍历对象的指针就从函数头部往下偏移,开始执行函数内部的代码,直到遇到第一个yield表达式就停止函数的执行,并返回一个独对象;
② 当第二次调用next()方法时,遍历对象的指针就从第一个yield表达式的位置往下偏移,执行函数内的代码, 直到遇到下一个yield表达式;
③ 如果没有新的yield表达式,就一直运行到函数结束,直到遇到return语句就终止函数的进行,并将return关键字后面的值做为value值;
④ 如果该函数没有return语句,就将value置为undefined。
网友评论