1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-06-09 07:15:29 +00:00

edit generator

This commit is contained in:
ruanyf 2015-10-31 10:25:51 +08:00
parent 1b0805cb30
commit 6f98097df8
2 changed files with 112 additions and 59 deletions

@ -94,7 +94,7 @@ setTimeout(function () {
}, 2000);
```
上面代码中函数f如果是普通函数在为变量generator赋值时就会执行。但是函数f是一个Generator函数就变成只有调用next方法时函数f才会执行。
上面代码中,函数`f`如果是普通函数在为变量generator赋值时就会执行。但是函数`f`是一个Generator函数就变成只有调用`next`方法时,函数`f`才会执行。
另外需要注意yield语句不能用在普通函数中否则会报错。
@ -246,7 +246,7 @@ it.next(13)
// { value:42, done:true }
```
上面代码第一次调用next方法时返回`x+1`的值6第二次调用`next`方法,将上一次`yield`语句的值设为12因此`y`等于24返回`y / 3`的值8第三次调用`next`方法,将上一次`yield`语句的值设为13因此`z`等于13这时`x`等于5`y`等于24所以`return`语句的值等于42。
上面代码第一次调用`next`方法时,返回`x+1`的值6第二次调用`next`方法,将上一次`yield`语句的值设为12因此`y`等于24返回`y / 3`的值8第三次调用`next`方法,将上一次`yield`语句的值设为13因此`z`等于13这时`x`等于5`y`等于24所以`return`语句的值等于42。
注意,由于`next`方法的参数表示上一个`yield`语句的返回值,所以第一次使用`next`方法时不能带有参数。V8引擎直接忽略第一次使用`next`方法时的参数,只有从第二次使用`next`方法开始,参数才是有效的。
@ -414,7 +414,7 @@ try {
// 外部捕获 [Error: a]
```
上面代码之所以只捕获了a是因为函数体外的catch语句块捕获了抛出的a错误以后就不会再继续执行try语句块了。
上面代码之所以只捕获了`a`是因为函数体外的catch语句块捕获了抛出的`a`错误以后就不会再继续执行try语句块了。
如果Generator函数内部没有部署try...catch代码块那么throw方法抛出的错误将被外部try...catch代码块捕获。
@ -438,7 +438,7 @@ try {
// 外部捕获 a
```
上面代码中遍历器函数g内部没有部署try...catch代码块所以抛出的错误直接被外部catch代码块捕获。
上面代码中,遍历器函数`g`内部没有部署try...catch代码块所以抛出的错误直接被外部catch代码块捕获。
如果Generator函数内部部署了try...catch代码块那么遍历器的throw方法抛出的错误不影响下一次遍历否则遍历直接终止。
@ -682,6 +682,23 @@ function* bar() {
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
for (let v of foo()) {
console.log(v);
}
yield 'y';
}
for (let v of bar()){
console.log(v);
}
@ -691,7 +708,39 @@ for (let v of bar()){
// "y"
```
从另一个角度看,如果`yield`命令后面跟的是一个遍历器对象,需要在`yield`命令后面加上星号,表明它返回的是一个遍历器对象。这被称为`yield*`语句。
再来看一个对比的例子。
```javascript
function* inner() {
yield 'hello!';
}
function* outer1() {
yield 'open';
yield inner();
yield 'close';
}
var gen = outer1()
gen.next().value // "open"
gen.next().value // 返回一个遍历器对象
gen.next().value // "close"
function* outer2() {
yield 'open'
yield* inner()
yield 'close'
}
var gen = outer2()
gen.next().value // "open"
gen.next().value // "hello!"
gen.next().value // "close"
```
上面例子中,`outer2`使用了`yield*``outer1`没使用。结果就是,`outer1`返回一个遍历器对象,`outer2`返回该遍历器对象的内部值。
从语法角度看,如果`yield`命令后面跟的是一个遍历器对象,需要在`yield`命令后面加上星号,表明它返回的是一个遍历器对象。这被称为`yield*`语句。
```javascript
let delegatedIterator = (function* () {
@ -738,38 +787,6 @@ function* concat(iter1, iter2) {
上面代码说明,`yield*`不过是`for...of`的一种简写形式,完全可以用后者替代前者。
再来看一个对比的例子。
```javascript
function* inner() {
yield 'hello!';
}
function* outer1() {
yield 'open';
yield inner();
yield 'close';
}
var gen = outer1()
gen.next().value // "open"
gen.next().value // 返回一个遍历器对象
gen.next().value // "close"
function* outer2() {
yield 'open'
yield* inner()
yield 'close'
}
var gen = outer2()
gen.next().value // "open"
gen.next().value // "hello!"
gen.next().value // "close"
```
上面例子中,`outer2`使用了`yield*``outer1`没使用。结果就是,`outer1`返回一个遍历器对象,`outer2`返回该遍历器对象的内部值。
如果`yield*`后面跟着一个数组,由于数组原生支持遍历器,因此就会遍历数组成员。
```javascript
@ -782,6 +799,20 @@ gen().next() // { value:"a", done:false }
上面代码中,`yield`命令后面如果不加星号,返回的是整个数组,加了星号就表示返回的是数组的遍历器对象。
实际上任何数据结构只要有Iterator接口就可以被`yield*`遍历。
```javascript
let read = (function* () {
yield 'hello';
yield* 'hello';
})();
read.next().value // "hello"
read.next().value // "h"
```
上面代码中,`yield`语句返回整个字符串,`yield*`语句返回单个字符。因为字符串具有Iterator接口所以被`yield*`遍历。
如果被代理的Generator函数有`return`语句那么就可以向代理它的Generator函数返回数据。
```javascript
@ -840,7 +871,7 @@ for(let x of iterTree(tree)) {
// e
```
下面是一个稍微复杂的例子使用yield*语句遍历完全二叉树。
下面是一个稍微复杂的例子,使用`yield*`语句遍历完全二叉树。
```javascript
// 下面是二叉树的构造函数,

@ -5,19 +5,23 @@
ES6允许直接写入变量和函数作为对象的属性和方法。这样的书写更加简洁。
```javascript
// 示例一
var foo = 'bar';
var baz = {foo};
baz // {foo: "bar"}
// 等同于
var baz = {foo: foo};
```
baz // Object {foo: "bar"}
上面代码表明ES6允许在对象之中只写属性名不写属性值。这时属性值等于属性名所代表的变量。下面是另一个例子。
// 示例二
```javascript
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
@ -25,7 +29,7 @@ function f(x, y) {
f(1, 2) // Object {x: 1, y: 2}
```
上面代码表明ES6允许在对象之中只写属性名。这时属性值等于属性名所代表的变量。除了属性简写,方法也可以简写。
除了属性简写,方法也可以简写。
```javascript
var o = {
@ -72,23 +76,6 @@ getPoint()
// {x:1, y:10}
```
赋值器和取值器,也可以采用简洁写法。
```javascript
var cart = {
_wheels: 4,
get wheels () {
return this._wheels
},
set wheels (value) {
if (value < this._wheels) {
throw new Error('hey, come back here!')
}
this._wheels = value
}
}
```
模块输出变量,就非常合适使用简洁写法。
```javascript
@ -107,6 +94,41 @@ function clear () {
}
module.exports = { getItem, setItem, clear };
// 等同于
module.exports = {
getItem: getItem,
setItem: setItem,
clear: clear
};
```
属性的赋值器setter和取值器getter事实上也是采用这种写法。
```javascript
var cart = {
_wheels: 4,
get wheels () {
return this._wheels;
},
set wheels (value) {
if (value < this._wheels) {
throw new Error('数值太小了!');
}
this._wheels = value;
}
}
```
如果某个方法的值是一个Generator函数前面需要加上星号。
```javascript
var obj = {
* m(){
yield 'hello world';
}
}
```
## 属性名表达式