Generator函数,能够理解为一种状态机,封装了多个内部状态。是一个遍历器生成器,返回遍历器对象(即Generator 函数的内部指针)。bash
Generator函数和普通函数区别:函数
function* foo(){
console.log('hello');
}
var bar = foo();
bar.next();
bar.next();
//'hello'
复制代码
一个普通函数中使用yield表达式,结果产生一个句法错误ui
(function(){
yield 1;
})(); // 报错
(function*(){
yield 1;
})();//ok
复制代码
function* foo() {
console.log('start');
yield 1;
console.log('middle');
yield 2;
console.log('end');
return 3;
}
var bar = foo();
console.log(bar.next());
console.log(bar.next());
console.log(bar.next());
console.log(bar.next());
//start
//{ value: 1, done: false }
//middle
//{ value: 2, done: false }
//end
//{ value: 3, done: true }
//{ value: undefined, done: true }
复制代码
Generator函数的运行流程:this
区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具有位置记忆的功能。spa
yield表达式自己没有返回值,或者说老是返回undefined。yield表达式若是用在另外一个表达式之中,必须放在圆括号里面指针
function* foo() {
//在另外一个表达式中,yield表达式必须加上圆括号
console.log( 'hello' + (yield 'world'));
}
var bar = foo();
console.log(bar.next());
console.log(bar.next());
//{ value: 'world', done: false }
//helloundefined
//{ value: undefined, done: true }
复制代码
yield表达式用做函数参数或放在赋值表达式的右边,能够不加括号code
function fun(a){
console.log('a:'+ a);
}
function* foo() {
fun(yield 'hello', yield 'world'); //函数参数
let value = yield; //表达式右侧
}
var bar = foo();
console.log(bar.next());
console.log(bar.next());
console.log(bar.next());
console.log(bar.next());
//{ value: 'hello', done: false }
//{ value: 'world', done: false }
//a:undefined
//{ value: undefined, done: false }
//{ value: undefined, done: true }
复制代码
任意一个对象的Symbol.iterator方法等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。对象
Generator 函数执行后,返回一个遍历器对象。该对象自己也具备Symbol.iterator属性,执行后返回自身。接口
function* foo() {
yield 1;
}
var bar = foo();
bar === bar[Symbol.iterator]() //true
复制代码
Generator 函数赋值给Symbol.iterator属性,从而使得myIterable对象具备了 Iterator 接口,能够被...运算符遍历了generator
var myIterable = {};
myIterable[Symbol.iterator] = function* foo() {
yield 1;
yield 2;
};
[...myIterable] //[1, 2]
复制代码
next方法能够带一个参数,该参数就会被看成上一个yield表达式的返回值
function* foo() {
let a = 10;
let b = yield 10 + a;
yield b + 10;
}
var bar = foo();
bar.next(); //{ value: 20, done: false }
bar.next(20); //{ value: 30, done: false }
bar.next(); //{ value: undefined, done: true }
复制代码
第二个next参数20做为,第一次yield的返回值,全部b = 20 ,因此第二个yield表达式为值为30
Generator 函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。经过next方法的参数,就有办法在 Generator 函数开始运行以后,继续向函数体内部注入值。
for...of循环遍历Iterator对象,再也不须要调用next方法
function* foo() {
yield 1;
yield 2;
return 3;
}
for (let v of foo()) {
console.log(v);
}//1 2
复制代码
须要注意,一旦next方法的返回对象的done属性为true,for...of循环就会停止,且不包含该返回对象,因此上面代码的return语句返回的3,不包括在for...of循环之中
for...of循环、扩展运算符(...)、解构赋值和Array.from方法内部调用的,都是遍历器接口。这意味着,它们均可以将 Generator 函数返回的 Iterator 对象,做为参数。
使对象类型数据也能使用for...of 第一种
function* foo() {
let keys = Object.keys(this);
for (let key of keys) {
yield [key, this[key]];
}
}
var bar = { name: 'li', age: 20};
bar[Symbol.iterator] = foo;
for (let value of bar) {
console.log(value);
}
//[ 'name', 'li' ]
//[ 'age', 20 ]
复制代码
第二种实现
function* foo(obj) {
let keys = Object.keys(obj);
for(let key of keys){
yield [key, obj[key]];
}
}
var bar = {name: 'li', age: 20, sex: 'man'};
for (let value of foo(bar)){
console.log(value);
}
复制代码
generator.throw()抛出错误先看内部又没有捕获,若是内部没有捕获,就外部捕获。若是都没有捕获,那么程序将报错,直接中断执行。
注意区分throw方法和全局的throw
function* foo() {
try{
yield 1;
} catch(error){
console.log('error');
}
yield 2;
}
var bar = foo();
bar.next(); //{ value: 1, done: false }
bar.throw();//{ value: 2, done: false }
throw new Error('xxx');
复制代码
若是return方法传有参数就当作返回对象的value值。日后再调用next方法都返回{ value: undefined, done: true }
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next(); //{ value: 1, done: false }
g.return('foo'); //{ value: 'foo', done: true }
g.next(); //{ value: undefined, done: true }
复制代码
若是Generator中有try...finaly,调用return()方法后,就开始执行finally代码块,不执行try里面剩下的代码了,而后等到finally代码块执行完,再返回return()方法指定的返回
function* gen() {
try {
yield 1;
yield 2;
} finally {
yield 3;
yield 4;
}
}
var g = gen();
g.next();//{ value: 1, done: false }
g.return('foo');//{ value: 3, done: false }
g.next(); //{ value: 4, done: false }
g.next(); //{ value: 'foo', done: true }
g.next(); //{ value: undefined, done: true }
复制代码
在 Generator 函数内部,调用另外一个 Generator 函数。
function* foo() {
yield 1;
yield* bar();
yield 2;
}
function* bar() {
yield 3;
yield 4;
}
var g = foo();
[...g];//[ 1, 3, 4, 2 ]
复制代码