# 深入產生器函式

``````function* range(start, end) {
for(let i = start; i < end; i++) {
yield i;
}
return 'return';
}
``````

`for` 迴圈之後，程式最後使用 `return` 試圖傳回 `'return'` 字串，來看看執行的結果：

``````> let g = range(1, 3);
undefined
> g.next();
{ value: 1, done: false }
> g.next();
{ value: 2, done: false }
> g.next();
{ value: 'return', done: true }
>
``````

``````> let g2 = range(1, 3);
undefined
> for(let i of g2) {
...     console.log(i);
... }
1
2
undefined
>
``````

``````> function* range(start, end) {
...     for(let i = start; i < end; i++) {
.....         yield i;
.....     }
... }
undefined
> let g = range(1, 3);
undefined
> g.next();
{ value: 1, done: false }
> g.return();
{ value: undefined, done: true }
> let g2 = range(1, 3);
undefined
> g2.next();
{ value: 1, done: false }
> g2.return(10);
{ value: 10, done: true }
>
``````

`return` 方法會在先前 `yield` 處進行 `return`，此時傳回的物件 `done` 特性會是 `true``value` 特性會是 `undefined`，如果 `return` 方法有指定引數，那麼傳回的物件 `done` 特性會是 `true``value` 特性會是指定的引數。

``````> let g = range(1, 3);
undefined
> g.next();
{ value: 1, done: false }
> g.throw('Orz');
Thrown: Orz
> let g2 = range(1, 3);
undefined
> g2.next();
{ value: 1, done: false }
> g2.throw(new Error('XD'));
Error: XD
at repl:1:10
at ContextifyScript.Script.runInThisContext (vm.js:50:33)
at REPLServer.defaultEval (repl.js:240:29)
at bound (domain.js:301:14)
at REPLServer.runBound [as eval] (domain.js:314:12)
at REPLServer.onLine (repl.js:441:10)
at emitOne (events.js:121:20)
at REPLServer.emit (events.js:211:7)
>
``````

``````> let g = range(1, 3);
undefined
> g instanceof range;
true
> g.__proto__ == range.prototype;
true
>
``````

``````> let g2 = new range(1, 3);
TypeError: range is not a constructor
at repl:1:10
at ContextifyScript.Script.runInThisContext (vm.js:50:33)
at REPLServer.defaultEval (repl.js:240:29)
at bound (domain.js:301:14)
at REPLServer.runBound [as eval] (domain.js:314:12)
at REPLServer.onLine (repl.js:441:10)
at emitOne (events.js:121:20)
at REPLServer.emit (events.js:211:7)
>
``````

`range``prototype` 上，`constructor` 特性也不是參考 `range`

``````> range.prototype.constructor === range;
false
>
``````

``````> function* range(start, end) {
...     for(this.i = start; this.i < end; this.i++) {
.....         yield this.i;
.....     }
... }
undefined
> let g = range(1, 3);
undefined
> g.next();
TypeError: Cannot set property 'i' of undefined
at range (repl:2:16)
at range.next (<anonymous>)
at repl:1:3
at ContextifyScript.Script.runInThisContext (vm.js:50:33)
at REPLServer.defaultEval (repl.js:240:29)
at bound (domain.js:301:14)
at REPLServer.runBound [as eval] (domain.js:314:12)
at REPLServer.onLine (repl.js:441:10)
at emitOne (events.js:121:20)
at REPLServer.emit (events.js:211:7)
>
``````

``````> let o = {};
undefined
> let g = range.call(o, 1, 3);
undefined
> g.next();
{ value: 1, done: false }
> o.i;
1
> g.next();
{ value: 2, done: false }
> o.i;
2
> g.i;
undefined
>
``````

``````> function* range(obj, start, end) {
...     for(obj.i = start; obj.i < end; obj.i++) {
.....         yield obj.i;
.....     }
... }
undefined
> let o = {};
undefined
> let g = range(o, 1, 3);
undefined
> g.next();
{ value: 1, done: false }
> o.i;
1
> g.next();
{ value: 2, done: false }
> o.i;
2
>
``````