## 21.3 用作迭代器的生成器（数据生产）

``````interface Iterable {
[Symbol.iterator]() : Iterator;
}
interface Iterator {
next() : IteratorResult;
return?(value? : any) : IteratorResult;
}
interface IteratorResult {
value : any;
done : boolean;
}
``````

``````function* genFunc() {
yield 'a';
yield 'b';
}
``````

``````> let genObj = genFunc();
> genObj.next()
{ value: 'a', done: false }
> genObj.next()
{ value: 'b', done: false }
> genObj.next() // done: true => end of sequence
{ value: undefined, done: true }
``````

### 21.3.1 迭代一个生成器的方式

``````for (let x of genFunc()) {
console.log(x);
}
// Output:
// a
// b
``````

``````let arr = [...genFunc()]; // ['a', 'b']
``````

``````> let [x, y] = genFunc();
> x
'a'
> y
'b'
``````

### 21.3.2 从生成器返回

``````function* genFuncWithReturn() {
yield 'a';
yield 'b';
return 'result';
}
``````

`next()` 返回的最后一个对象包含了返回值，并且对象的属性 `done``true`

``````> let genObjWithReturn = genFuncWithReturn();
> genObjWithReturn.next()
{ value: 'a', done: false }
> genObjWithReturn.next()
{ value: 'b', done: false }
> genObjWithReturn.next()
{ value: 'result', done: true }
``````

``````for (let x of genFuncWithReturn()) {
console.log(x);
}
// Output:
// a
// b

let arr = [...genFuncWithReturn()]; // ['a', 'b']
``````

`yield*` 是一个执行生成器嵌套调用的操作符，它会考虑 `done` 属性里面的值，这在后面讲解。

### 21.3.3 示例：迭代属性

``````function* objectEntries(obj) {
// In ES6, you can use strings or symbols as property keys,
// Reflect.ownKeys() retrieves both
let propKeys = Reflect.ownKeys(obj);

for (let propKey of propKeys) {
yield [propKey, obj[propKey]];
}
}
``````

``````let jane = { first: 'Jane', last: 'Doe' };
for (let [key,value] of objectEntries(jane)) {
console.log(`\${key}: \${value}`);
}
// Output:
// first: Jane
// last: Doe
``````

``````function objectEntries(obj) {
let index = 0;
let propKeys = Reflect.ownKeys(obj);

return {
[Symbol.iterator]() {
return this;
},
next() {
if (index < propKeys.length) {
let key = propKeys[index];
index++;
return { value: [key, obj[key]] };
} else {
return { done: true };
}
}
};
}
``````

### 21.3.4 只能在生成器中使用 `yield`

``````function* genFunc() {
['a', 'b'].forEach(x => yield x); // SyntaxError
}
``````

``````function* genFunc() {
for (let x of ['a', 'b']) {
yield x; // OK
}
}
``````

### 21.3.5 通过 `yield*` 嵌套（用于输出）

``````function* foo() {
yield 'a';
yield 'b';
}
``````

``````function* bar() {
yield 'x';
foo(); // does nothing!
yield 'y';
}
``````

``````function* bar() {
yield 'x';
yield* foo();
yield 'y';
}

// Collect all values yielded by bar() in an array
let arr = [...bar()];
// ['x', 'a', 'b', 'y']
``````

``````function* bar() {
yield 'x';
for (let value of foo()) {
yield value;
}
yield 'y';
}
``````

`yield*` 的操作数不一定是生成器对象，也可以是可迭代的对象：

``````function* bla() {
yield 'sequence';
yield* ['of', 'yielded'];
yield 'values';
}

let arr = [...bla()];
// ['sequence', 'of', 'yielded', 'values']
``````

#### 21.3.5.1 用 `yield*` 拿到最后一个值

``````function* genFuncWithReturn() {
yield 'a';
yield 'b';
return 'The result';
}
function* logReturned(genObj) {
let result = yield* genObj;
console.log(result); // (A)
}
``````

``````> [...logReturned(genFuncWithReturn())]
The result
[ 'a', 'b' ]
``````

#### 21.3.5.2 遍历树

``````class BinaryTree {
constructor(value, left=null, right=null) {
this.value = value;
this.left = left;
this.right = right;
}

/** Prefix iteration */
* [Symbol.iterator]() {
yield this.value;
if (this.left) {
yield* this.left;
}
if (this.right) {
yield* this.right;
}
}
}
``````

``````let tree = new BinaryTree('a',
new BinaryTree('b',
new BinaryTree('c'),
new BinaryTree('d')),
new BinaryTree('e'));

for (let x of tree) {
console.log(x);
}
// Output:
// a
// b
// c
// d
// e
``````