Generator 生成器
一个例子让你理解Generator语法
- 理解:
- 从语法上讲,generator是一个状态机,它封装着其内部很多的状态
- 执行一个generator函数,会返回一个迭代器对象(有next()方法,可以手动单步访问内部代码)
例子
function* foo(){
console.log('hi!'); // hi!
let a = yield 'hello';
yield console.log(a); // aaaa
return 'world!';
}
let generator = foo(); // 返回迭代器实例(指针对象)
console.log(generator.next('111')); //{value: "hello", done: false}
console.log(generator.next('aaaa')); // {value: undefined, done: false}
console.log(generator.next()); // {value: "world!", done: true}
console.log(generator.next()); //{value: undefined, done: true}
打印结果
hi!
{value: “hello”, done: false}
aaaa
{value: undefined, done: false}
{value: “world!”, done: true}
{value: undefined, done: true}
分析
- 定义generator函数,只需在function 与 方法名之间加个*。yield后面只能接表达式或函数调用语句
- 调用foo后,只会返回一个指针对象,不会执行里面的代码
- 调用第一个next()时,代码从函数第一行运行,直到遇到yield命令,把yield里面的语句执行完,代码停止,next()调用完后返回一个{value: xxx, done:xxx}对象,value是yield表达式的返回结果,第一yield后面只有一个 ‘hello’ 字符串,其实相当于返回 ‘hello’(跟箭头函数差不多)
- 我们调用第一、第二个next方法的时候,都传入了一个参数,但是第一next(‘111’)没有起作用,而第二个next(‘aaa’),最后console.log(a)中有输出。这是因为next()传参的原因。当我们调用第二个next()时,generator里面的代码上一次运行完后停止在了第一个yield一行,这是运行第二个next的起点,这时第二next()传入的’aaa’,就会被let a = yield … 这一行的变量 a 接收。同样,第二次运行代码会在遇到第二个yield,并运行完其后面的语句后再次停止。但是调用的next()返回对象中value=undefined,这是因为conslog.log(a) 执行完后输出了’aaa’,函数不能显式设置返回值,就会返回undefined
- 第3次调用next(),会使函数里面的代码继续从上一次结束的点开始再次执行,发现最后没有了yield,那就会执行到底。整个函数所有代码执行完毕,这时next()返回值为{value:‘world!’,done:true},value是函数最后的返回值,done表示函数所有代码执行完毕。如果函数没有返回值,value=undefined.
- 第4次调用next(),函数已经执行完了,还调用就会返回{value:undefined, done:true}.第5第6次调用还是同样的值,这是迭代器的特性。
总结
- generator是惰性求值的,如果你调用next()方法就不会运行函数里面的代码
- yield有点类似于代码调试里的断点,在多个yield之间,每调用一次next()就运行一段代码。
- next()参数会把参数传到上一次结束yield位置,如果有值接收,就把值传为它。由于第一次调用,没有上一次的说法,所以第一调用next()不能传参,如果要传,只能从调用generator函数时传入。
- gennerator就是返回一个迭代器对象,跟使用iterator对象差不多。