From 6f98097df84b6c57ebc47c7029c696078e583876 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 31 Oct 2015 10:25:51 +0800 Subject: [PATCH] edit generator --- docs/generator.md | 107 ++++++++++++++++++++++++++++++---------------- docs/object.md | 64 ++++++++++++++++++--------- 2 files changed, 112 insertions(+), 59 deletions(-) diff --git a/docs/generator.md b/docs/generator.md index 349480e..0fb19c6 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -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 // 下面是二叉树的构造函数, diff --git a/docs/object.md b/docs/object.md index dd96cb8..7337e34 100644 --- a/docs/object.md +++ b/docs/object.md @@ -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'; + } +} ``` ## 属性名表达式