From 8c06336a27eb25e0e5f7869dfc30ae52e4a4c2e1 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 5 Sep 2016 14:04:01 +0800 Subject: [PATCH] =?UTF-8?q?docs(generator):=20=E4=BD=BF=E7=94=A8=20for...o?= =?UTF-8?q?f=20=E5=BE=AA=E7=8E=AF=E4=BE=9D=E6=AC=A1=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E9=A2=84=E5=AE=9A=E7=9A=84=E6=93=8D=E4=BD=9C=E6=AD=A5=E9=AA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/generator.md | 90 +++++++++++++++++++++++++++++++++++------------ docs/reference.md | 1 + 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/docs/generator.md b/docs/generator.md index 658d6ec..4e75f41 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -309,7 +309,7 @@ genObj.next('b') ## for...of循环 -`for...of`循环可以自动遍历调用Generator函数时生成的Iterator对象,且此时不再需要调用`next`方法。 +`for...of`循环可以自动遍历Generator函数时生成的`Iterator`对象,且此时不再需要调用`next`方法。 ```javascript function *foo() { @@ -346,34 +346,49 @@ for (let n of fibonacci()) { } ``` -从上面代码可见,使用`for...of`语句时不需要使用next方法。 +从上面代码可见,使用`for...of`语句时不需要使用`next`方法。 -前面章节曾经介绍过,`for...of`循环、扩展运算符(`...`)、解构赋值和`Array.from`方法内部调用的,都是遍历器接口。这意味着,它们可以将Generator函数返回的Iterator对象,作为参数。 +由于`for...of`循环会自动依次执行`yield`命令,这启发我们可以将一些按步骤操作的任务,写在Generator函数里面。 ```javascript -function* numbers () { - yield 1 - yield 2 - return 3 - yield 4 +let steps = [step1Func, step2Func, step3Func]; + +function *iterateSteps(steps){ + for (var i=0; i< steps.length; i++){ + var step = steps[i]; + yield step(); + } } - -[...numbers()] // [1, 2] - -Array.from(numbers()) // [1, 2] - -let [x, y] = numbers(); -x // 1 -y // 2 - -for (let n of numbers()) { - console.log(n) -} -// 1 -// 2 ``` -利用`for...of`循环,可以写出遍历任意对象的方法。原生的JavaScript对象没有遍历接口,无法使用`for...of`循环,通过Generator函数为它加上这个接口,就可以用了。 +上面代码中,数组`steps`封装了一个任务的多个步骤,Generator函数`iterateSteps`则是依次为这些步骤加上`yield`命令。 + +将任务分解成步骤之后,还可以将项目分解成多个依次执行的任务。 + +```javascript +let jobs = [job1, job2, job3]; + +function *iterateJobs(jobs){ + for (var i=0; i< jobs.length; i++){ + var job = jobs[i]; + yield *iterateSteps(job.steps); + } +} +``` + +上面代码中,数组`jobs`封装了一个项目的多个任务,Generator函数`iterateJobs`则是依次为这些任务加上`yield *`命令(`yield *`命令的介绍详见后文)。 + +最后,就可以用`for...of`循环一次性依次执行所有任务的所有步骤。 + +```javascript +for (var step of iterateJobs(jobs)){ + console.log(step.id); +} +``` + +注意,上面的做法只能用于所有步骤都是同步操作的情况,不能有异步操作的步骤。如果想要依次执行异步的步骤,必须使用下一章介绍的方法。 + +利用`for...of`循环,可以写出遍历任意对象(object)的方法。原生的JavaScript对象没有遍历接口,无法使用`for...of`循环,通过Generator函数为它加上这个接口,就可以用了。 ```javascript function* objectEntries(obj) { @@ -415,6 +430,35 @@ for (let [key, value] of jane) { // last: Doe ``` +除了`for...of`循环以外,扩展运算符(`...`)、解构赋值和`Array.from`方法内部调用的,都是遍历器接口。这意味着,它们都可以将Generator函数返回的Iterator对象,作为参数。 + +```javascript +function* numbers () { + yield 1 + yield 2 + return 3 + yield 4 +} + +// 扩展运算符 +[...numbers()] // [1, 2] + +// Array.form 方法 +Array.from(numbers()) // [1, 2] + +// 解构赋值 +let [x, y] = numbers(); +x // 1 +y // 2 + +// for...of 循环 +for (let n of numbers()) { + console.log(n) +} +// 1 +// 2 +``` + ## Generator.prototype.throw() Generator函数返回的遍历器对象,都有一个`throw`方法,可以在函数体外抛出错误,然后在Generator函数体内捕获。 diff --git a/docs/reference.md b/docs/reference.md index 2b24084..739693f 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -151,6 +151,7 @@ - Mahdi Dibaiee, [ES7 Array and Generator comprehensions](http://dibaiee.ir/es7-array-generator-comprehensions/):ES7的Generator推导 - Nicolas Bevacqua, [ES6 Generators in Depth](http://ponyfoo.com/articles/es6-generators-in-depth) - Axel Rauschmayer, [ES6 generators in depth](http://www.2ality.com/2015/03/es6-generators.html): Generator规格的详尽讲解 +- Derick Bailey, [Using ES6 Generators To Short-Circuit Hierarchical Data Iteration](https://derickbailey.com/2015/10/05/using-es6-generators-to-short-circuit-hierarchical-data-iteration/) ## Promise对象