JavaScript生成器

来源:互联网 时间:1970-01-01

一.语法

创建语法: function* + yield

使用语法: next(returnValue).value/done

P.S. 迭代器生成器: function*定义的东西叫迭代器的生成器(简称生成器),因为调用它返回一个迭代器

二.迭代器的作用 1.函数节流

把时耗多的复杂任务用yield分成小块慢慢做,也叫函数柯里化currying,更多信息请查看 JS学习笔记11_高级技巧

2.生成无限序列

比如斐波那契数列

3.方便遍历

不用手动维护内部状态

三.JavaScript生成器实例 1.基本用法 function* fun(a) {yield a + 1;yield a * 2;yield a * 2 + 1;}var iter = fun(3);iter.next();// => Object {value: 4, done: false}iter.next();// => Object {value: 6, done: false}iter.next();// => Object {value: 7, done: false}function* fun(a) {yield a=a + 1;yield a=a * 2;yield a=a * 2 + 1;}var iter = fun(3);// => iter.next();Object {value: 4, done: false}iter.next();// => Object {value: 8, done: false}iter.next();// => Object {value: 17, done: false}iter.next();// => Object {value: undefined, done: true}

函数执行遇到 yield,先return yield后面的值,再保存函数执行的context(效果类似于保存断点),下一次调用 next()时,恢复context,从yield的下一句开始执行,遇到yield或者return退出

2.高级用法 function* fib() {var a = 1;var b = 1;while (true) {var current = b;b = a;a = a + current;var reset = yield current;if (reset) {a = 1;b = 1;}}}var fibSeq = fib();fibSeq.next();// => Object {value: 1, done: false}fibSeq.next();// => Object {value: 1, done: false}fibSeq.next();// => Object {value: 2, done: false}fibSeq.next();// => Object {value: 3, done: false}fibSeq.next();// => Object {value: 5, done: false}fibSeq.next(false);// => Object {value: 8, done: false}fibSeq.next(true);// => Object {value: 1, done: false}fibSeq.next(false);// => Object {value: 1, done: false}fibSeq.next(false);// => Object {value: 2, done: false}

next()可以接受参数,此参数会被当做yield的返回值传回函数,这样就可以控制函数内部的状态,例如上面的是否reset

3.比较绕的例子 function* fun(a) {a = yield a + 1;a = yield a * 2;yield a * 2 + 1;}var iter = fun(3);iter.next(0);// => Object {value: 4, done: false}iter.next(0);// => Object {value: 0, done: false}iter.next(1);// => Object {value: 3, done: false}类似的:function* fun(a) {a = yield a = a + 1;a = yield a = a * 2;yield a = a * 2 + 1;}var iter = fun(3);iter.next(0);// => Object {value: 4, done: false}iter.next(0);// => Object {value: 0, done: false}iter.next(1);// => Object {value: 3, done: false}

内部执行机制一样,只是写法比较绕

4.其它

此外,迭代器还有 throw()和 return()方法, FF都实现了,Chrome只实现了前者,更多信息请查看 MDN Iterators and generators

还有利用1个迭代器生成另一个迭代器的语法,例如:

function* fun() {yield 1;yield 2;}var iter = fun();var newIter = (for (i of iter) i * 2);newIter.next();// => Object { value: 2, done: false }newIter.next();// => Object { value: 4, done: false }

注意,MDN的例子有误,必须是for…of,且必须是圆括号(例子中的for…in和方括号都是错的)

FF支持这种语法,Chrome不支持

三.相关语法 1.for…of、for…in、forEach

for…of用来遍历属性值,for…in用来遍历属性名,forEach是Array.prototype上的方法,能同时遍历属性名和属性值

此外,for…of也能遍历DOM NodeList和自定义的迭代器(function* + yield),是ES6的新东西

实例如下:

var arr = [3, 5, 7];arr.foo = "hello";for (var i in arr) {console.log(i); // logs "0", "1", "2", "foo"}for (var i of arr) {console.log(i); // logs "3", "5", "7"}let arr = [3, 5, 7];arr.foo = "hello";arr.forEach(function (element, index) { console.log(element); // logs "3", "5", "7" console.log(index);// logs "0", "1", "2"}); 2.yield*

与 yield功能类似,也是用来遍历的,但 yield*后面跟迭代器对象,作用是进入后面的迭代器,遍历完再回来,例如:

function* g1() { yield 2; yield 3; yield 4;}function* g2() { yield 1; yield* g1(); yield 5;}var iterator = g2();console.log(iterator.next()); // { value: 1, done: false }console.log(iterator.next()); // { value: 2, done: false }console.log(iterator.next()); // { value: 3, done: false }console.log(iterator.next()); // { value: 4, done: false }console.log(iterator.next()); // { value: 5, done: false }console.log(iterator.next()); // { value: undefined, done: true }

有了 yield*后,迭代器可以嵌套了,可以“线性”遍历层级结构(当然,前提是拿到所有下层结构的迭代器对象)

参考资料



相关阅读:
Top