本文是ES6学习的第二部分,主要学习的是生成器(GENERATORS)
GENERATORS与以前的JS特性截然不同,但是却使语言内部的常态行为变得更加强大
ES6生成器简介
首先用一个例子介绍生成器是什么?
上述代码看起来像一个函数,但是它是一个生成器函数,他们之间不同之处:
- 普通函数使用 function 声明,而生成器函数使用 function*声明。
- 在生成器函数内部,有一种类似 return 的语法:关键字 yield。二者的区别是,普
通函数只可以 return 一次,而生成器函数可以 yield 多次(当然也可以只 yield 一次)。
在生成器的执行过程中,遇到 yield 表达式立即暂停,后续可恢复执行状态。
这就是普通函数和生成器函数之间最大的区别,普通函数不能自暂停,生成器函数
可以
生成器做了什么?
生成器的调用“quips("jorendorff")“,但是它并未立即执行,而是返回了一个已暂停的生成器对象(iter)
它在调用一次后被冻结了。每一次调用.next()方法时,函数调用将其自身解冻并一直运行到下一个yield表达式,每次调.next()直到生成器末尾,返回值结果中done = true,value=undefined。
如果用专业术语描述,每当生成器执行 yields 语句,生成器的堆栈结构(本地变量、参数、临时值、生成器内部当前的执行位置)被移出堆栈。然而,生成器对象保留了对这个堆栈结构的引用(备份),所以稍后调用.next()可以重新激活堆栈结构并且继续执行。
生成器不是线程,当生成器运行时,它和调用者处于同一线程中,拥有确定的连续执行顺序,永不并发。与系统线程不同的是,生成器只有在其函数体内标记为 yield 的点才会暂停。
生成器是迭代器
首先实现一个迭代器,创建一个简单的迭代器。可以实现两个数字之间的所以数相加,首先是传统C的for(;;)循环。
使用ES6的语法解决
由上面的例子可以看出生成器是迭代器,所有生成器都内建有.next()和[Symbol,iterator]()方法的实现。
例子2:简化数组构建函数
使用生成器创建的代码如下:
使用生成器是使用生成器返回一个迭代器,每次根据需要逐一地计算,而传统写法是计算所有结果并返回一个数组类型的结果。
当面对一个复杂的循环时,可以拆分出生成数据的代码,将其转换为独立的生成器函数,然后使用for(var data of myNewGenerator(args))遍历所要的数据 。
举个例子,假设你需要一个等效于 Array.prototype.filter 并且支持 DOM NodeLists
的方法,可以这样写:
生成器与异步代码
异步API通常需要一个回调函数,意味着需要为每次执行编写额外的异步函数,所以如果有有一段代码需要完
成三个任务,你将看到类似的三层级缩进的代码,而非简单的三行代码。
到目前为止,异步代码不如同步代码美观又简洁。
实验性的 Q.async()尝试结合 promises 使用生成器产生异步代码的等效同步代码。举个例子:
二者主要的区别是,异步版本必须在每次调用异步函数的地方添加 yield 关键字。在 Q.async 版本中添加一个类似 if 语句的判断或 try/catch 块,如同向同步版本中添加类似功能一样简单。
如何应用这些疯狂的新特性?
在服务器端,现在你可以在 io.js 中使用 ES6(在 Node 中你需要使用--harmony 这
个命令行选项)。
在浏览器端,到目前为止只有 Firefox 27+和 Chrome 39+支持了 ES6 生成器。如果要在 web 端使用生成器,你需要使用 Babel 或 Traceur 来将你的 ES6 代码转译为 Web友好的 ES5
Yield
未完待续
参考资料《ES6-In-Depth》