《ECMAScript6入门》笔记——Generator函数

时间:2022-09-13 23:27:44

今天在看《ECMAScript6入门》的第17章——Generator函数的语法。理解起来还是有点费劲,几段代码看了很多遍。总算有点点理解了。

示例代码如下:(摘自阮一峰《ECMAScript 6 入门》)

function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
} var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true} var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }

看到这段代码的时候有点懵逼~

首先回顾一下generator知识点:

  1. Generator函数的特征之一:function关键字与函数名之间有一个星号*
  2. Generator函数体内部使用yield表达式——产出
  3. 每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止
  4. yield表达式与return语句的区别:
    • 每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能。
    • 一个函数里面,只能执行一次return语句,可以执行多次yield表达式。
  5. Generator函数可以返回一系列的值,因为可以有任意多个yield
  6. yield表达式只能用在generator函数里面,用在普通函数中会报错。
  7. yield表达式本身没有返回值,或者说总是返回undefined。
  8. next方法可以带一个参数,该参数会被当做上一个yield表达式的返回值。
  9. done属性:表示是否遍历结束。

现在再来仔细看一遍上面那段代码:

首先,定义一个generator函数

// 定义一个generator函数
function* foo(x) {
var y = 2 * (yield (x + 1)); // 第一次调用next方法时,返回第一个yield表达式的值; done:false
var z = yield (y / 3); // 第二次调用next方法时,返回第二个yield表达式的值; done:false
return (x + y + z); // 第三次调用next方法时,返回return语句的值;done:true
}
// 如果还有第四次调用next方法,返回value:undefined,done:true

不向next方法提供参数时:

var a = foo(5); // 调用generator函数foo,生成一个遍历器对象a;此时x = 5
a.next() // Object{value:6, done:false} 第一次调用next(),启动遍历器对象;此时x=5;返回foo中第一个yield表达式的值,x + 1(即5+1)等于6
a.next() // Object{value:NaN, done:false} 第二次调用next();此时x=5;由于next缺少参数,导致上一个(即第一个)yield表达式的值为undefined;y = 2 * undefined,即y等于NaN;z = NaN/3,即z等于NaN,因此第二个yield也是返回NaN
a.next() // Object{value:NaN, done:true} 第三次调用next();此时x=5;由于next缺少参数,导致上一个(即第二个)yield表达式的值为undefined,也就是z等于undefined;因此return返回值是 5 + NaN + undefined,即NaN

向next方法提供参数时:

var b = foo(5); // 调用generator函数foo,生成一个遍历器对象b; 此时x=5
b.next() // { value:6, done:false } 第一个调用next,不用传值,启动遍历器对象;此时x=5;返回值是第一个yield表达式 x+1等于6
b.next(12) // { value:8, done:false } 第二次调用next,将上一次yield表达式的值设为12,因此y等于2*12,即24;第二个yield返回24/3,即8,同时z=8;
b.next(13) // { value:42, done:true } 第三次调用next,将上一次yield表达式的值设为13,因此z=13;此时x=5,y=24,所以return语句的值是42

参考:阮一峰《ECMAScript 6 入门》第17章Generator 函数的语法