es6的Generator函数
2016-04-17 17:36
375 查看
摘自Generator 函数
Generator函数是协程在ES6的实现,最大特点就是可以交出函数的执行权(即暂停执行)。
整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield语句注明。
Generator函数有多种理解角度。从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。
function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hello = helloWorldGenerator(); hello.next();// {value: "hello", done: false} hello.next();// {value: "world", done: false} hello.next();// {value: "ending", done: true} hello.next();// {value: undefined, done: true}
调用Generator函数,返回一个遍历器对象,代表
Generator函数的内部指针。以后,每次调用遍历器对象的
next方法,就会返回一个有着
value和
done两个属性的对象。
value属性表示当前的内部状态的值,是
yield语句后面那个表达式的值;
done属性是一个布尔值,表示是否遍历结束。
next
方法的参数
yield句本身没有返回值,或者说总是返回
undefined。
next方法可以带一个参数,该参数就会被当作上一个
yield语句的返回值。
function* gen(){ var x = yield "a"; var y = yield "b"; return x + y; } var g = gen(); g.next(); // {value: "a", done: false} g.next("hello"); // {value: "b", done: false} g.next("world"); // {value: "helloworld", done: true}
第一个
next返回
yield "a";的value值
a,第二个
next返回
yield "b";的value值”b”。
但是
next接收参数
hello作为上一个
yield "a"语句的返回值,
x的值为
hello.
第三个
next接收参数
world作为上一个
yield "b"语句的返回值,
y的值为
world.
return返回的值就是
helloworld
var g = gen(); g.next();//{value: "a", done: false} g.next();//{value: "b", done: false} //`next`方法没有传入参数时,`yield`语句返回`undefined`. undefined + undefined => NaN g.next();//{value: "NaN", done: true}
第一个next方法用来执行完第一个
yield语句,所以不用带有参数。
如果想要第一次调用next方法时,就能够输入值,可以在Generator函数外面再包一层。
function wrapper(generatorFunction) { return function (...args) { var generatorObject = generatorFunction(...args); generatorObject.next(); return generatorObject; }; } const wrapped = wrapper(function* () { var result = yield "hello"; return result; }); wrapped().next('world');
yield*
语句
如果在Generator函数内部,调用另一个Generator函数,默认情况下时没有效果的。"use strict" function* foo(){ yield "a"; yield "b"; } function* bar(){ yield "x"; foo(); yield "y"; } for (let v of bar()){ console.log(v); }
上面代码中,
foo和
bar都是Generator函数,在
bar里面调用
foo,是没有效果的
这个就需要用到
yield*语句,用来在一个Generator函数里面执行另一个Generator函数。
function* bar() { yield 'x'; yield* foo(); yield 'y'; } // 等同于 function* bar() { yield 'x'; yield 'a'; yield 'b'; yield 'y'; } // 等同于 function* bar() { yield 'x'; for (let v of foo()) { yield v; } yield 'y'; } for (let v of bar()){ console.log(v); }
yield*不过是
for...of的一种简写形式,完全可以用后者替代前者。
任何数据结构只要有
Iterator接口,就可以被
yield*遍历。
function* foo() { yield 'hello'; yield* 'hello'; } for (let v of foo()){ console.log(v); }
如果被代理的Generator函数有
return语句,那么可以向代理它的Generator函数返回数据。
function* foo(){ yield 2; yield 3; return "foo"; } function* bar(){ yield 1; var v = yield *foo(); console.log("v:",v); yield 4; } for (let v of bar()){ console.log(v); }
作为对象属性的Generator
函数
let obj = { * myGeneratorMethod(){ yield 1; } }
上面代码中,
myGeneratorMethod属性前面有一个星号,表示这个属性是一个
Generator函数
它的完整形式如下,与上面的写法是等价的。
let obj = { myGeneratorMethod:function*(){ yield 1; } }
Generator函数的this
Generator函数总是返回一个遍历器,ES6规定这个遍历器是Generator函数的实例,也继承了Geenraotr函数的prototype对象上的方法。
function* g() {} g.prototype.hello = function () { return 'hi!'; }; let obj = g(); obj instanceof g; // true obj.hello(); // 'hi!'
上面代码表明,
Generator函数g返回的遍历器
obj,是
g的实例,而且继承了
g.prototype。
但是,如果把
g当作普通的构造函数,并不会生效,因为
g返回的总是遍历器对象,而不是
this对象。
function* g(){ this.a = 11; } let obj = g(); obj.a;//undefined
Generator与状态机
Generator是实现状态机的最佳结构。下面的clock函数就是一个状态机。var ticking = true; var clock = function(){ if(ticking) console.log("Tick!"); else console.log("Tock!"); ticking = !ticking; }
上述代码的clock函数一共有两种状态(Tick和Tock),每运行一次,就改变一次状态。
var clock = function*(){ while(true){ console.log("Tick!"); yield; console.log("Tock!"); yield; } }
相关文章推荐
- Python之我见
- linux解压文件出错gzip: stdin: invalid compressed data--format violated
- 第四章:android核心组件之SimpleAdapter适配器构造函数的详解(二)
- Android开发更新UI的几种方式
- java第五次作业
- POJ 1003
- 软件工程概述
- python中的random模块学习
- 求a~b内与n互素的数的个数 容斥原理
- 主元素-----lintcode
- ubuntu 15.10 安装swift开发环境 2016/4/17
- 20145309 实验二
- CSU 1711 Kinfolk【模拟】
- 聚集索引和非聚集索引
- 希尔排序
- 约瑟夫环and同余方程组模板(exgcd求解同余方程组)
- POJ 1002
- VGScene(firemonkey前身)布局设置
- 【简易版】IOS仿periscope自制狂赞飘桃心
- 【Leetcode146】LRU Cache