以下章節 由淺入深 帶大家探索 Generator function!
🌱 🌿 🌳
🌱
它封裝多個內部狀態,而 yield 是一個暫停標誌。
function* generator() {
yield 'state1';
yield 'state2';
}
function* speak() {
yield 'hello';
yield 'world';
}
const iterator = speak();
function* speak() {
yield 'hello';
yield 'world';
}
const i = speak();
i.next(); // { value: 'hello', done: false }
i.next(); // { value: 'world', done: false }
i.next(); // { value: undefined, done: true }
function* speak() {
yield 'hello';
yield 'world';
return '!';
}
const i = speak();
i.next(); // { value: 'hello', done: false }
i.next(); // { value: 'world', done: false }
i.next(); // { value: '!', done: true } -> done 已經是 true,而 value 取得的是 return 的值
i.next(); // { value: undefined, done: true }
function getName() {
console.log('My name is world.');
return 'world';
}
function* speak() {
yield 'hello ' + getName();
}
const i = speak();
i.next(); // My name is world.
// { value: 'hello world', done: false }
// 不一定要使用 yield
function* speak() {}
// 但是 yield 一定要在 generator function 中使用
function speak() {
yield 'hello world'; // Error!
}
// 在表達式中必須加括弧
console.log('hello' + (yield 'world'));
// 在參數中不用
getName(yield 'Who are you?');
function* conversation() {
const name = yield 'What\'s your name?'; // name 會取得第二個 next 回傳的參數
yield `Ok, your name is ${name}, right?`;
}
const i = conversation();
i.next().value; // What's your name?
i.next('Jason').value; // Ok, your name is Jason, right?
const i = conversation();
i.next().value;
i.next('Jason').value;
function* foo(x) {
const y = 2 * (yield (x + 1));
const z = yield (y / 3);
return (x + y + z);
}
const i = foo(5);
console.log(i.next().value);
console.log(i.next(12).value);
console.log(i.next(13).value);
function* foo(x) {
const y = 2 * (yield (x + 1));
const z = yield (y / 3);
return (x + y + z);
}
const i = foo(5); // x=5
console.log(i.next().value); // yield x+1 -> 6
console.log(i.next(12).value); // y=2*12 -> yield 24/3 -> 8
console.log(i.next(13).value); // z=13 -> 5+24+13 -> 42
- 它是一個狀態機
- 它會回傳一個遍歷器
- 使用
next()
遍歷狀態 - 在
next()
中傳入參數,與 generator 互動
🌿
function *foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
// 1 2 3 4 5
// 注意:沒有 `return` 的值
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
for (let n of fibonacci()) {
if (n > 1000) break;
console.log(n);
}
function* numbers () {
yield 1
yield 2
return 3
yield 4
}
Array.from(numbers()) // [1, 2]
[...numbers()] // [1, 2]
let [x, y] = numbers(); // x=1, y=2
for (let n of numbers()) {
console.log(n);
}
// 1 2
function* g() {
try {
yield;
} catch (e) {
console.log('内部捕獲', e);
}
}
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('外部捕獲', e);
}
// 內部捕獲, a
// 外部補獲, b
function* g() {
try {
yield console.log('a');
} catch (e) {
// ...
}
yield console.log('b');
yield console.log('c');
}
var i = g();
i.next(); // a
i.throw(); // b
i.next(); // c
function* g() {
yield 1;
yield 2;
yield 3;
}
var i = g();
i.next(); // { value: 1, done: false }
i.return('foo'); // { value: 'foo', done: true }
i.next(); // { value: undefined, done: true }
function* numbers() {
yield 1;
try {
yield 2;
yield 3;
} finally {
yield 4;
yield 5;
}
yield 6;
}
var i = numbers()
i.next(); // { done: false, value: 1 }
i.next(); // { done: false, value: 2 }
i.return(7); // { done: false, value: 4 }
i.next(); // { done: false, value: 5 }
i.next(); // { done: true, value: 7 }
function* foo() {
yield 'a';
yield 'b';
}
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
for (let v of bar()) {
console.log(v);
}
// x a b y
function* g() {
yield* ['a', 'b', 'c'];
}
g().next() // { value: 'a', done: false }
let read = (function* () {
yield 'hello';
yield* 'hello';
})();
read.next().value // 'hello'
read.next().value // 'h'
function* foo() {
yield 2;
yield 3;
return 'foo';
}
function* bar() {
yield 1;
var v = yield* foo();
console.log('v: ' + v);
yield 4;
}
var i = bar();
i.next(); // { value: 1, done: false }
i.next(); // { value: 2, done: false }
i.next(); // { value: 3, done: false }
i.next(); // 'v: foo'
// { value: 4, done: false }
i.next(); // { value: undefined, done: true }
const obj = {
* myGeneratorMethod() {
···
}
};
我們介紹了以下語法:
- for…of
- Generator.prototype.throw
- Generator.prototype.return
- yield*
- 當物件屬性是 generator
🌳
function* g() {}
g.prototype.hello = function () {
return 'hi!';
};
const obj = g();
obj instanceof g; // true
obj.hello(); // 'hi!'
function* g() {
this.a = 11;
}
let obj = g();
obj.a; // undefined
function* F() {
yield this.x = 2;
yield this.y = 3;
}
new F()
// TypeError: F is not a constructor
- 以同步化的方式撰寫異步操作
- 控制流管理
- 部署 iterator 接口
- 作為數據結構
🎓