学ES6的时候,我一般会先看一些讲ES6的视频,对要学的概念有个大致的理解之后,再来看阮老师的文章,嗯、每次都会有,原来如此的感觉,阮老师讲的真的很详细,也很好理解,整理一遍是希望能把老师讲的理解的更深入一点,如果您也想要了解这一章的内容建议到阮老师的官方网站看原版,很好很详细http://es6.ruanyifeng.com/#docs/generator
Generator函数是ES6提供的一种异步编程解决方案,它有多种理解角度,语法上可以理解Generator是一个状态机,封装了多个内部状态。执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。
Generator函数的特点:
1、、function关键字与函数名之间有一个星号
2、函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)
function * fn(){
yield "leo";
yield "donna";
return "welcome zhengzhou";
}
var p1 = fn();
console.log(p1);
该函数有三个状态:leo、donna、return语句(结束执行)
Generator函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用Generator函数后,该函数并不执行,返回的也不是函数运行的结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)
下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态
调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针,以后每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前内部状态的值,是yield表达式后面那个表达式的值,done属性是一个布尔值,表示是否遍历结束。
嗯、看例子喽
function * fn(){
yield "leo";
yield "donna";
return "welcome zhengzhou";
}
var p1 = fn();
console.log(p1.next());//{value: "leo", done: false}
console.log(p1.next());//{value: "donna", done: false}
console.log(p1.next());//{value: "welcome zhengzhou", done: true}
它的执行过程大概就是:第一次调用,Generator函数开始执行,知道遇到第一个yield表达式为止,next返回第一个对象,它的value属性就是当前yield表达式值leo,done的属性值false,表示遍历还没有结束。第二次调用,Generator函数从上次yield表达式停下来的地方,一直执行到下一个yield,value属性和done属性和第一个一样,就这样,依次调用执行,直到执行到return语句,(如果没有return语句,就执行到函数结束)。value属性的值,就是紧跟在return语句后面的表达的值(如果没有return语句,则value属性的值为undefined),done属性的值为true,表示遍历已经结束。如果你还想要再次调用,那么value属性的为undefined,done属性的值为true。以后每次调用都为这个值。
注意:由于Generator函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
yield表达式和return语句的对比:
- 相似处:两者都能返回紧跟在语句后面的那个表达式
- 不同处:每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆功能
- 一个函数里面,只能执行一次return语句,但是可以执行多次yield表达式
- 正常函数只能返回一个值,(因为只能执行一次return),Generator函数可以返回一系列的值
Generator函数可以不用yield表达式,这时就变成一个单纯的暂缓执行函数。但yield表达式只能用在Generator函数里面,用在其他地方会报错。
另外,yield表达式如果用在另一个表达式之中,必须放在圆括号里面,yield表达式用作函数参数或者放在赋值表达式的右边,可以不加括号。
function * fn(){
yield "leo";
yield "donna";
//console.log("leo"+(yield));//Uncaught SyntaxError: Unexpected identifier
console.log("leo"+(yield));//正确的写法
return "welcome zhengzhou";
}
function* fn() {
fn(yield 'a', yield 'b'); // OK
let a= yield; // OK
}
for…of循环:可以自动遍历Generator函数时生成的Iterator对象,且此时不需要调用next方法。
不过,一旦next方法的返回对象的done属性为true,for…of循环就会中止,且不包含返回对象,也就是不包含return后面的值
function * fn(){
yield "leo";
yield "donna";
return "welcome zhengzhou";
}
var p1 = fn();
for(let i of p1){
console.log(i);//leo、donna
}
除了for…of循环以外,扩展运算符(…)、解构赋值和Array.from()方法内部调用的,都是遍历器接口,这意味着,他们都可以将Generator函数返回的Iterator对象,作为参数
function * fn(){
yield "leo";
yield "donna";
return "welcome zhengzhou";
}
var p1 = fn();
//console.log(...p1);//leo,donna
//console.log(Array.from(p1));//["leo","donna"]
let [x,y,z] = p1;
console.log(x,y,z);//leo donna undefined
嗯、今天就先总结这么多太多了感觉都记混了,先把前面的学好了,后面的就学着轻松了。