1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

修改generator

This commit is contained in:
Ruan Yifeng 2014-12-26 05:44:02 +08:00
parent ef6bd9d6fa
commit 956a8860cc

View File

@ -52,7 +52,7 @@ hw.next()
由于Generator函数返回的遍历器只有调用next方法才会遍历下一个成员所以其实提供了一种可以暂停执行的函数。yield语句就是暂停标志next方法遇到yield就会暂停执行后面的操作并将紧跟在yield后面的那个表达式的值作为返回对象的value属性的值。当下一次调用next方法时再继续往下执行直到遇到下一个yield语句。如果没有再遇到新的yield语句就一直运行到函数结束将return语句后面的表达式的值作为value属性的值如果该函数没有return语句则value属性的值为undefined。另一方面由于yield后面的表达式直到调用next方法时才会执行因此等于为JavaScript提供了手动的“惰性求值”Lazy Evaluation的语法功能。
yield语句与return语句有点像都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield函数暂停执行下一次再从该位置继续向后执行而return语句不具备位置记忆的功能。
yield语句与return语句有点像都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield函数暂停执行下一次再从该位置继续向后执行而return语句不具备位置记忆的功能。一个函数里面只能执行一次或者说一个return语句但是可以执行多次或者说多个yield语句。正常函数只能返回一个值因为只能执行一次returnGenerator函数可以返回一系列的值因为可以有任意多个yield。
Generator函数可以不用yield语句这时就变成了一个单纯的暂缓执行函数。
@ -70,32 +70,7 @@ setTimeout(function () {
```
上面代码中函数f如果是普通函数在为generator变量赋值时就会执行。但是函数f是一个Generator函数就变成只有调用next方法时函数f才会执行。
利用Generator函数可以在任意对象上部署iterator接口。
```javascript
function* iterEntries(obj) {
let keys = Object.keys(obj);
for (let i=0; i < keys.length; i++) {
let key = keys[i];
yield [key, obj[key]];
}
}
let myObj = { foo: 3, bar: 7 };
for (let [key, value] of iterEntries(myObj)) {
console.log(key, value);
}
// foo 3
// bar 7
```
上述代码中myObj是一个普通对象通过iterEntries函数就有了iterator接口。也就是说可以在任意对象上部署next方法。
上面代码中函数f如果是普通函数在为变量generator赋值时就会执行。但是函数f是一个Generator函数就变成只有调用next方法时函数f才会执行。
## next方法的参数
@ -145,9 +120,58 @@ it.next(13)
注意由于next方法的参数表示上一个yield语句的返回值所以第一次使用next方法时不能带有参数。V8引擎直接忽略第一次使用next方法时的参数只有从第二次使用next方法开始参数才是有效的。
## 异步操作的应用
## for...of循环
Generator函数的这种暂停执行的效果意味着可以把异步操作写在yield语句里面等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了因为异步操作的后续操作可以放在yield语句下面反正要等到调用next方法时再执行。所以Generator函数的一个重要实际意义就是用来处理异步操作改写回调函数。
for...of循环可以自动遍历Generator函数且此时不再需要调用next方法。
```javascript
function *foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
// 1 2 3 4 5
```
上面代码使用for...of循环依次显示5个yield语句的值。这里需要注意一旦next方法的返回对象的done属性为truefor...of循环就会中止且不包含该返回对象所以上面代码的return语句返回的6不包括在for...of循环之中。
下面是一个利用generator函数和for...of循环实现斐波那契数列的例子。
```javascript
function* fibonacci() {
let [prev, curr] = [0, 1];
for (;;) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
for (let n of fibonacci()) {
if (n > 1000) break;
console.log(n);
}
```
从上面代码可见使用for...of语句时不需要使用next方法。
## 应用
Generator可以暂停函数执行返回任意表达式的值。这种特点使得Generator有多种应用场景。
### 1异步操作的同步化表达
Generator函数的暂停执行的效果意味着可以把异步操作写在yield语句里面等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了因为异步操作的后续操作可以放在yield语句下面反正要等到调用next方法时再执行。所以Generator函数的一个重要实际意义就是用来处理异步操作改写回调函数。
```javascript
@ -209,6 +233,8 @@ function* numbers() {
上面代码打开文本文件使用yield语句可以手动逐行读取文件。
### 2控制流管理
总结一下如果某个操作非常耗时可以把它拆成N步。
```javascript
@ -258,60 +284,36 @@ function* f(){
上面代码使用Promise的函数库Qyield语句返回的就是一个Promise对象。
## for...of循环
### 3部署iterator接口
for...of循环可以自动遍历Generator函数且此时不再需要调用next方法
利用Generator函数可以在任意对象上部署iterator接口
```javascript
function *foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
function* iterEntries(obj) {
let keys = Object.keys(obj);
for (let i=0; i < keys.length; i++) {
let key = keys[i];
yield [key, obj[key]];
}
}
for (let v of foo()) {
console.log(v);
let myObj = { foo: 3, bar: 7 };
for (let [key, value] of iterEntries(myObj)) {
console.log(key, value);
}
// 1 2 3 4 5
// foo 3
// bar 7
```
面代码使用for...of循环依次显示5个yield语句的值。这里需要注意一旦next方法的返回对象的done属性为truefor...of循环就会中止且不包含该返回对象所以上面代码的return语句返回的6不包括在for...of循环之中
述代码中myObj是一个普通对象通过iterEntries函数就有了iterator接口。也就是说可以在任意对象上部署next方法
下面是一个利用generator函数和for...of循环实现斐波那契数列的例子。
### 4作为数据结构
```javascript
function* fibonacci() {
let [prev, curr] = [0, 1];
for (;;) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
for (let n of fibonacci()) {
if (n > 1000) break;
console.log(n);
}
```
从上面代码可见使用for...of语句时不需要使用next方法。
## 作为数据结构的Generator
Generator可以暂停函数执行返回任意表达式的值。这种特点使得Generator有多种应用场景。
- 异步操作的同步化表达abstractions of async behavior
- 控制流管理control flow management
- 数据结构data structure)
第一种和第二种应用在本章前面部分已经有所提及了。这里主要再补充一下Generator可以看作是数据结构因为它可以对任意表达式提供类似数组的接口。
Generator可以看作是数据结构更确切地说可以看作是一个数组结构因为Generator函数可以返回一系列的值这意味着它可以对任意表达式提供类似数组的接口。
```javascript