~~~~~今天看前端代码的时候,看到很多yield关键字,所以就来学习下yield是什么~~~~~~~~
The yield keyword is used to pause and resume a generator function. // yield这个关键字是用来暂停和恢复一个遍历器函数(的运行)的
所以可以看出来,es6的yield跟python中的yield关键字用法是非常类似的,如果了解python的生成器,那么这篇就很好理解了。。。
#语法
[rv] = yield [expression];
遍历器函数Generator
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。 执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。 形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。 function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator(); 上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)
#遍历器函数语法
function *foo(){
...
[rv] = yield [expression];
...
}
所以yield是跟generator一起使用的,现在我们来看下如何用
var a=0;
function *foo(){
a+=1;
yield a;
}
var f=foo();
alert a;
浏览器控制台执行下,结果是0,证明并没有执行foo()内的代码。原因是调用生成器函数只是生成一个遍历器对象。要想执行,必须是next()方法
代码更改如下:
var a=0;
function *foo(){
a+=1;
yield a;
}
var f=foo();
f.next();
alert(a);
再次执行,弹框是1,证明执行了foo函数。
每次执行next(),都是循环一次函数体,我们看下执行的过程
我们看到上面执行的yield返回结果是一个value,一个done值,done表示的就是是否遍历完成。false就是没遍历完成,true是遍历结束。
当 运行到yield的时候,程序暂停了,不会继续执行。而当遇到return的时候,表示遍历结束,看下面的两个例子
特点:
所以生成器跟普通函数的区别是,你需要跟他要值,他才给。要一个给一个,给完了,他就没有了。或者一下子要过来,他就变空了。
var a = 0; function *foo() { a += 1; yield ''; return; } var f = foo(); #执行下面的代码 var s1 = f.next(); console.log(s1); // {value: '',done: false}yield返回的是空字符串,所以value是空字符串,然后遍历暂停,不会执行return。 var s2 = f.next(); console.log(s2); // {value: undefined,done: true} 第一次暂停后,继续往下执行return,但是return返回的是空,所以value是undefined。一旦return,遍历即结束,所以done为true
var a = 0;
function *foo() {
a += 1;
yield a;
a+=3;
return a;
}
var f = foo();
s1=f.next();
console.log(s1); // {value: 1,done: false}s2=f.next();
console.log(s2); // {value: 4,done: true}
那接下来,我们来学习下.next()的参数,没错,next()函数可以传参。
看下我从别处拉来的几行代码
var foo = function *() { // 没错,尼玛还可以这样写 var x = 1; var y = yield (x + 1); var z = yield (x + y); return z; }() // 你必须先执行一下Generator函数,才能把遍历器返回给某个变量 var a = foo.next(); // 第一次执行next()不可以传参 var b = foo.next(3); var c = foo.next(4);
求abc的值?
a显而易见,就是返回的(x+1)=2
b为foo.next(3),这个3是啥意思,是传给上一个yield的值,这时可以把yield当做一个参数。也就是说y被赋值3,b为(x+y)=4
foo.next(4),就是把4赋值给了上一个yield值即z,所以c就是最后return的值4。
OK,相信你已经看懂了,那再看看下一段代码:
var log = function *() {
a=yield 1; console.log(`you input: ${a}`) }();
log.next(); log.next('hello world!');
结果:Object { value: undefined, done: true
结果:
you input: hello world!
Object { value: undefined, done: true },
原因:1. log.next() 执行到yield 1结束。注意,这时的a并不是1。
2. log.next('hello world!') 执行,会把‘hello world!’ 赋值给参数a,从上次yield语句后开始执行,所以会打印出--》you input: hello world!
3. undefined,是因为已经没有yield了,所以undefined
var log = function *() { a=yield 1; console.log(`you input: ${a}`) }(); log.next(); log.next();#不传参数的话,a相当于没有赋值,会报undefined。所以如果想用a,必须传参
结果:
you input: undefined
{value: undefined, done: true}
总结一下
写了这么多,总结一下yield,实际上:
- 只能在Generator函数内部使用
- 运行.next(),遇到一个yield命令,就暂停
- .next()的返回值表示一个状态{value,done}
- 再运行.next(),从之前遇到的那个yield [表达式]处(后)继续恢复运行
- 当.next()传参的时候,yield [表达式]整个被替换为传入的参数。