你不知道的javascript读书笔记(生成器)

440 阅读3分钟

完整运行

一般的函数从开始运行为止就会一直到结束为止不会被打断,期间更不会被其他代码打断并插入期间了
而生成器(generator)正好能解决这个问题
下面来看一下生成器的语法吧:

var x = 1;
function *foo(){
    x++;
    yield; //暂停
    console.log("x:",x)
}
function bar(){
    x++;
}


var it = foo(); //(1)
it.next(); //(2)
console.log(x);
bar(); //(3)
console.log(x);
it.next(); //(4)

1.it=foo()运算并没有执行生成器 *foo(),只是构造了一个迭代器(注意不带 *号)
2.启动了生成器 *foo(),并运行 *foo()的第一行的x++;这时走到yield时会暂停语句,这时候it.next()调用结束,此时对 *foo()仍在运行并且是活跃对,但处于暂停状态
3.执行函数x++(实现了函数在执行但时候插入代码)
4.再次执行it.next(),*foo()从暂停状态转回活跃状态,继续执行暂停之后的语句,并从控制台打印x,此时的x是由bar()执行后的值--x:3

有趣的迭代消息传递

function *foo(x){
    var y = x * (yield);
    return y;
}
var it = foo(6); //(1)
it.next(); //(2)
var res = it.next(7); //(3)

console.log(res.value); //(4)

1.it = foo(6)这个迭代器中,是可以和正常函数一样,传入参数的
2.当2执行生成器的时候遇到yield停下来
3.将x再赋值,为7,此时迭代的内容就是 var y = 6 * 7(yield相当于递归调用自己,把结果值赋值给yield)
4.it.next()实际上如果存在return返回值的话,那么它下面的value属性是把return返回的值赋值给本身,因此res.value = (return) y;如果不存在,那就是undefined(普遍未经过声明或声明未赋初始值的都是undefined)

function *foo(x){
    var y = x * (yield "hello")
    return y;
}
1.var it = foo(6);
2.console.log(it.next())  //{value:"hello",done:false};
3.console.log(it.next(7)) //{value:42,done:true};

实际的数据在上述代码块中的流动是这样的:done:false,

首先
1.赋值定义一个迭代器it,同时赋值x=6
2.执行生成器it.next(),可以看到生成器中有两个属性done和value,第一次的执行生成器遇到yield时,如果yield有值,就把值赋值给value,因为是暂停了函数,所以函数未完成done的值为false
3.执行第二次生成器时,赋值x = 7,相当于yield处替换为下一次执行的生成器传入的参数

多个迭代器

function *foo(){
   var x = yield 2;
   z++;
   var y = yield(x*z);
   console.log(x,y,z)
}
var z = 1;
var it1 =  foo();
var it2 =  foo();

var val1 = it1.next().value; //2(1)
var val2 = it2.next().value; //2(2)

val1 = it1.next(val2 * 10).value; //40(3)
val2 = it2.next(val1 * 5).value;  //600(4)

流程分析:
1.构造一个迭迭代器val1;
2.构造另外一个迭代器val2(此时已经证明新构建的迭代器不影响之前的迭代器,如果影响的话val的value就等于x*z了)
3和4分别是在不同数据下,生成器的运行过程
3.传入参数val2(2)10 = 20,此时执行的是第一个yield后的代码块,即:
x = val2
10 = 20;z++后z=2;当遇到第二个yield时,暂停函数,此时的value等于第二个yield后执行返回的结果->x * z = 20 * 2 = 40;
最后val1重新赋值,值为40
4.同异地个生成器第二个生成器走第一个yield后的代码块,只是此时的传入的参数不同,值为val1 * 5 = 40 * 5 =200;value等于第二个yield后执行后返回的结果, val2 = x * z = 200 * 3(z++递增后) = 600

由此可见生成器使函数的交替执行成为了可能

因为能力有限,实践暂时更不上理论,现在需要沉淀以下,多写代码多理解后,再回头来看后面多内容以及回顾前面多章节来提升自己多理解和感悟