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

docs(generator): edit Generator

This commit is contained in:
ruanyf 2017-09-06 11:41:09 +08:00
parent ba08efe8d1
commit 4dbd9b0f48

View File

@ -265,6 +265,27 @@ b.next(13) // { value:42, done:true }
注意,由于`next`方法的参数表示上一个`yield`表达式的返回值,所以在第一次使用`next`方法时传递参数是无效的。V8 引擎直接忽略第一次使用`next`方法时的参数,只有从第二次使用`next`方法开始,参数才是有效的。从语义上讲,第一个`next`方法用来启动遍历器对象,所以不用带有参数。 注意,由于`next`方法的参数表示上一个`yield`表达式的返回值,所以在第一次使用`next`方法时传递参数是无效的。V8 引擎直接忽略第一次使用`next`方法时的参数,只有从第二次使用`next`方法开始,参数才是有效的。从语义上讲,第一个`next`方法用来启动遍历器对象,所以不用带有参数。
再看一个通过`next`方法的参数,向 Generator 函数内部输入值的例子。
```javascript
function* dataConsumer() {
console.log('Started');
console.log(`1. ${yield}`);
console.log(`2. ${yield}`);
return 'result';
}
let genObj = dataConsumer();
genObj.next();
// Started
genObj.next('a')
// 1. a
genObj.next('b')
// 2. b
```
上面代码是一个很直观的例子,每次通过`next`方法向 Generator 函数输入值,然后打印出来。
如果想要第一次调用`next`方法时,就能够输入值,可以在 Generator 函数外面再包一层。 如果想要第一次调用`next`方法时,就能够输入值,可以在 Generator 函数外面再包一层。
```javascript ```javascript
@ -287,27 +308,6 @@ wrapped().next('hello!')
上面代码中Generator 函数如果不用`wrapper`先包一层,是无法第一次调用`next`方法,就输入参数的。 上面代码中Generator 函数如果不用`wrapper`先包一层,是无法第一次调用`next`方法,就输入参数的。
再看一个通过`next`方法的参数,向 Generator 函数内部输入值的例子。
```javascript
function* dataConsumer() {
console.log('Started');
console.log(`1. ${yield}`);
console.log(`2. ${yield}`);
return 'result';
}
let genObj = dataConsumer();
genObj.next();
// Started
genObj.next('a')
// 1. a
genObj.next('b')
// 2. b
```
上面代码是一个很直观的例子,每次通过`next`方法向 Generator 函数输入值,然后打印出来。
## for...of 循环 ## for...of 循环
`for...of`循环可以自动遍历 Generator 函数时生成的`Iterator`对象,且此时不再需要调用`next`方法。 `for...of`循环可以自动遍历 Generator 函数时生成的`Iterator`对象,且此时不再需要调用`next`方法。
@ -599,7 +599,7 @@ try {
} }
``` ```
上面代码中,第二个`next`方法向函数体内传入一个参数42数值是没有`toUpperCase`方法的所以会抛出一个TypeError错误被函数体外的`catch`捕获。 上面代码中,第二个`next`方法向函数体内传入一个参数42数值是没有`toUpperCase`方法的,所以会抛出一个 TypeError 错误,被函数体外的`catch`捕获。
一旦 Generator 执行过程中抛出错误,且没有被内部捕获,就不会再执行下去了。如果此后还调用`next`方法,将返回一个`value`属性等于`undefined``done`属性等于`true`的对象,即 JavaScript 引擎认为这个 Generator 已经运行结束了。 一旦 Generator 执行过程中抛出错误,且没有被内部捕获,就不会再执行下去了。如果此后还调用`next`方法,将返回一个`value`属性等于`undefined``done`属性等于`true`的对象,即 JavaScript 引擎认为这个 Generator 已经运行结束了。
@ -649,7 +649,7 @@ log(g());
## Generator.prototype.return() ## Generator.prototype.return()
Generator函数返回的遍历器对象还有一个`return`方法可以返回给定的值并且终结遍历Generator函数。 Generator 函数返回的遍历器对象,还有一个`return`方法,可以返回给定的值,并且终结遍历 Generator 函数。
```javascript ```javascript
function* gen() { function* gen() {
@ -706,6 +706,44 @@ g.next() // { value: 7, done: true }
上面代码中,调用`return`方法后,就开始执行`finally`代码块,然后等到`finally`代码块执行完,再执行`return`方法。 上面代码中,调用`return`方法后,就开始执行`finally`代码块,然后等到`finally`代码块执行完,再执行`return`方法。
## next()、throw()、return() 的共同点
网友 vision57 提出,`next()``throw()``return()`这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换`yield`表达式。
`next()`是将`yield`表达式替换成一个值。
```javascript
const g = function* (x, y) {
let result = yield x + y;
return result;
};
const gen = g(1, 2);
gen.next(); // Object {value: 3, done: false}
gen.next(1); // Object {value: 1, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = 1;
```
上面代码中,第二个`next(1)`方法就相当于将`yield`表达式替换成一个值`1`。如果`next`方法没有参数,就相当于替换成`undefined`
`throw()`是将`yield`表达式替换成一个`throw`语句。
```javascript
gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y
// 替换成 let result = throw(new Error('出错了'));
```
`return()`是将`yield`表达式替换成一个`return`语句。
```javascript
gen.return(2); // Object {value: 2, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = return 2;
```
## yield* 表达式 ## yield* 表达式
如果在 Generator 函数内部,调用另一个 Generator 函数,默认情况下是没有效果的。 如果在 Generator 函数内部,调用另一个 Generator 函数,默认情况下是没有效果的。