未分类

ES6知识点梳理(5)

Generator

Generator是ES6提供的一种异步编程解决方案,它是一种状态机封装了多个内部对象,执行Generator函数会返回一个遍历器对象

形式上,Generator函数就是普通函数,但有两个特性
1.function命令与函数名之间有一个*
2.函数体内部使用yield语句定义不同的内部状态
eg:

1
2
3
4
5
6
function* helloGenerator(){
yield 'hello';
yield 'Generator';
return 'ending';
}
var hg = helloGenerator();

该函数有三个状态:hello、Generator和return语句(结束执行)

ps:Generator函数的调用与普通函数相同,但调用后Generator函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,即iterator对象,接下来就要使用next方法使得指针移向下一个状态。即每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一条yield语句(或return语句)为止。换言之,Generator函数是分段执行的,yield语句是暂停执行标记,而next方法可以恢复执行

yield语句使用注意事项

1.普通函数中使用yield语句报错
2.yield语句若要用在一个表达式中,必须放在圆括号里
3.yield语句用作函数参数或用于赋值表达式的右边,可以不加括号
根据语法规范,yield 的作用是代理 yield 表达式,将需要函数本身产生(yield)的值委托出去。yield 后面跟一个生成器函数、或其他可迭代的对象(如一个数组、字符串、arguments对象)。
yield
表达式的返回值,就是其后面可迭代对象迭代完毕时的返回值。*
eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var arr = [1,[[2,3],4],[5,6]];
var flat = function* (a){
var length = a.length;
for(var i = 0;i<length;i++){
var item = a[i];
if(typeof item !== 'number'){
yield* flat(item);
}else {
yield item;
}
}
};
for (var f of flat(arr)){
console.log(f);
}
// 1,2,3,4,5,6

next方法的参数

yield语句本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数会被当成上一条yield语句的返回值
eg:

1
2
3
4
5
6
7
8
9
10
function* foo(x){
var y = 2*(yield(x+1));
var z = yield(y/3);
return (x+y+z);
}

var b = foo(5);
b.next() // {value:6,done:false} y=x+1=6
b.next(12) // {value:8,done:false} y = 2*12 z = 24/3=8
b.next(13) // {value:42,done:true} z = 13 y = 24 x = 5 x+y+z = 42

for…of循环

for…of循环可以自动遍历Generator函数,且此时不再需要调用next方法(ps:一旦next方法的done属性为true则循环终止,且不包含该返回对象,比如不包含return出的值)

yield* 语句

如果在Generator函数中调用另一个Generator函数,默认是没效果的,默认返回一个遍历器对象,若用yield*返回遍历对象的内部值
eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
function* foo(){
yield 'a';
yield 'b';
}

function* bar(){
yield 'x';
foo();
yield 'y';
}
for(let v of bar()){
console.log(v); //"x" , "y"
}

这时,使用yield*语句(相当于在Generator函数内部部署一个for..of循环)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function* bar(){
yield 'x';
yield* foo();
yield 'y';
}

//等价于

function* bar(){
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}

作为对象属性的Generator函数

若函数的属性是Generator函数,可简写成如下形式

1
2
3
4
5
let obj = {
* myGeneratorMethod(){
...
}
}

完整形式

1
2
3
4
5
let obj = {
myGeneratorMethod: function* (){
//...
}
}

Generator函数的this

Generator函数总是返回一个遍历器(不返回this),ES6规定这个遍历器是Generator函数的实例,它是继承了Generator函数的prototype对象上的方法
用Generator函数作为构造函数时,直接new无法生成实例,因为返回一个内部指针
正确使用方法是:
生成一个空对象,使用bind方法绑定Generator函数内部的this,这样构造函数调用以后,这个空对象就是Generator函数的实例对象了

1
2
3
4
5
6
7
function* (){
yield this.x = 2;
yield this.y = 3;
}
var obj = {}
var f = F.bind(obj)();
//首先是F内部的this对象绑定obj对象,然后调用它,返回一个Iterator对象。