(Generator 函数的语法)
Generator 函数的语法
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
形式上,Generator 函数是一个普通函数,但是有两个特征。一是, function 关键字与函数名之
间有一个星号;二是,函数体内部使用 yield 表达式,定义不同的内部状态( yield 在英语里的
意思就是“产出”)。
1. function* helloWorldGenerator() { 2. yield 'hello'; 3. yield 'world'; 4. return 'ending'; 5. } 6. 7. var hw = helloWorldGenerator();
上面代码定义了一个 Generator 函数 helloWorldGenerator ,它内部有两个 yield 表达式
( hello 和 world ),即该函数有三个状态:hello,world 和 return 语句(结束执行)。
然后,Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,
调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的
指针对象,也就是上一章介绍的遍历器对象(Iterator Object)。
下一步,必须调用遍历器对象的 next 方法,使得指针移向下一个状态。也就是说,每次调
用 next 方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表
达式(或 return 语句)为止。换言之,Generator 函数是分段执行的, yield 表达式是暂停执
行的标记,而 next 方法可以恢复执行。
1. hw.next() 2. // { value: 'hello', done: false } 3. 4. hw.next() 5. // { value: 'world', done: false } 6. 7. hw.next() 8. // { value: 'ending', done: true } 9. 10. hw.next() 11. // { value: undefined, done: true }
第三次调用,Generator 函数从上次 yield 表达式停下的地方,一直执行到 return 语句(如果
没有 return 语句,就执行到函数结束)。 next 方法返回的对象的 value 属性,就是紧跟
在 return 语句后面的表达式的值(如果没有 return 语句,则 value 属性的值
为 undefined ), done 属性的值 true ,表示遍历已经结束。
第四次调用,此时 Generator 函数已经运行完毕, next 方法返回对象的 value 属性
为 undefined , done 属性为 true 。以后再调用 next 方法,返回的都是这个值。
总结一下,调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以
后,每次调用遍历器对象的 next 方法,就会返回一个有着 value 和 done 两个属性的对
象。 value 属性表示当前的内部状态的值,是 yield 表达式后面那个表达式的值; done 属性
是一个布尔值,表示是否遍历结束。
ES6 没有规定, function 关键字与函数名之间的星号,写在哪个位置。这导致下面的写法都能通
过。
1. function * foo(x, y) { ··· } 2. function *foo(x, y) { ··· } 3. function* foo(x, y) { ··· } 4. function*foo(x, y) { ··· }
由于 Generator 函数仍然是普通函数,所以一般的写法是上面的第三种,即星号紧跟
在 function 关键字后面。本书也采用这种写法。
yield 表达式
由于 Generator 函数返回的遍历器对象,只有调用 next 方法才会遍历下一个内部状态,所以其
实提供了一种可以暂停执行的函数。 yield 表达式就是暂停标志。
需要注意的是, yield 表达式后面的表达式,只有当调用 next 方法、内部指针指向该语句时才会
执行,因此等于为 JavaScript 提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。
1. function* gen() { 2. yield 123 + 456; 3. }
上面代码中, yield 后面的表达式 123 + 456 ,不会立即求值,只会在 next 方法将指针移到
这一句时,才会求值。
Generator 函数可以不用 yield 表达式,这时就变成了一个单纯的暂缓执行函数。
1. function* f() { 2. console.log('执行了!') 3. } 4. 5. var generator = f(); 6.
7. setTimeout(function () {
8. generator.next()
9. }, 2000);
上面代码中,函数 f 如果是普通函数,在为变量 generator 赋值时就会执行。但是,函数 f 是
一个 Generator 函数,就变成只有调用 next 方法时,函数 f 才会执行。
另外需要注意, yield 表达式只能用在 Generator 函数里面,用在其他地方都会报错。
1. (function (){ 2. yield 1; 3. })() 4. // SyntaxError: Unexpected number
上面代码在一个普通函数中使用 yield 表达式,结果产生一个句法错误。
for…of 循环
for...of 循环可以自动遍历 Generator 函数运行时生成的 Iterator 对象,且此时不再需要调用 next 方法。
1. function* foo() { 2. yield 1; 3. yield 2; 4. yield 3; 5. yield 4; 6. yield 5; 7. return 6; 8. } 9. 10. for (let v of foo()) { 11. console.log(v); 12. } 13. // 1 2 3 4 5
2021-05-21 17:26:39

浙公网安备 33010602011771号