1. 発電機の紹介
宣言: Generator 関数は ES6 によって提供される非同期プログラミング ソリューションです。複数の内部状態をカプセル化するステート マシンとみなすことができます。Generator 関数を実行するとトラバーサー オブジェクトが返されるため、トラバーサー オブジェクト生成関数でもあります。Generator関数も普通の関数ですが、2つの特徴があります。1 つ目は、function キーワードと関数名の間に * があること、2 つ目は、さまざまな内部状態を定義するために関数本体内で yield 式が使用されていることです。
function* fun() {
yield "张三" //状态1
yield "李四" //状态2
return "结束" //状态3
}
const obj = fun()
console.log(obj); //fun {<suspended>}
宣言: 返されるのは、内部状態を指すポインター オブジェクト、つまりトラバーサー オブジェクトです。
2. ジェネレーター機能はセグメントで実行されます
宣言: ジェネレーター関数はセグメントで実行され、yield 式は実行を一時停止するマーカーであり、次のメソッドは実行を再開できます。
console.log(obj.next()); //{value: '张三', done: false}
console.log(obj.next()); //{value: '李四', done: false}
console.log(obj.next()); //{value: '结束', done: true}
// 第三次调用Generator函数从上次yield表达式停下的地方,一直执行到下一个yield表达式。如果有retrun就执行到retrun
console.log(obj.next()); //{value: undefined, done: true}
3. 収量式
ステートメント: 関数のフラグを一時停止できる式。next() メソッドが呼び出されたときのみ、内部ポインタはステートメントを指します。これは遅延評価の構文関数とみなすことができます。
function* fun2(a, b) {
yield a + b
return a * 5
}
const obj2 = fun2(5, 6)
console.log(obj2); //fun2 {<suspended>}
console.log(obj2.next()); //{value: 11, done: false}
console.log(obj2.next()); //{value: 25, done: true}
console.log(obj2.return(5)); //{value: 5, done: true}
注: return と yield の違いは、関数内に return ステートメントは 1 つだけです。
4. 特殊なフォーム
説明: Genrator 関数は yield 式を必要としないため、純粋に遅延実行関数になります。
function* fun3() {
console.log("Hello world");
}
console.log(fun3().next());
//Hello world
//{value: undefined, done: true}
5.イールドエクスプレスの注意点
- yield 式は、Generator 関数でのみ使用できます。
- yield 式を別の式内で使用する場合は、その式を括弧で囲む必要があります。
function* fun4() {
console.log("你好" + (yield 123));
console.log("你好" + (yield 234));
}
const obj4 = fun4()
console.log(obj4.next()); //{value: 123, done: false}
console.log(obj4.next()); //{value: 234, done: false}
6. Iteratorインターフェースとの関係
説明: Generator 関数は反復子生成関数であるため、オブジェクトの Symbol.iterator プロパティに Generator を割り当てて、オブジェクトに Iterator インターフェイスを持たせることができます。
const myIter = {}
myIter[Symbol.iterator] = function* fun5() {
yield 1
yield 2
return 3
}
console.log(...myIter);
//1 2
説明: 結果 3 がない場合は、yield で宣言された式のみが走査されることを意味します。(返されたオブジェクトのdoneプロパティがtrueであるため、for...ofループは中止されます)
7. ジェネレーター関数はトラバーサー関数です
const fun6 = function* () {
}
const newFun6 = fun6()
console.log(newFun6 === newFun6[Symbol.iterator]()); //true
8. 次のメソッドのパラメータ
説明: 次のメソッドは、yield 式の戻り値として使用されるパラメーターを受け取ることができます。
function* fun7(x) {
let a = 4 * (yield (x + 1))
let b = yield (a / 3)
return (a + b + x)
}
const obj5 = fun7(1)
console.log(obj5.next()); //{value: 2, done: false}
console.log(obj5.next()); //{value: NaN, done: false}
console.log(obj5.next()); //{value: NaN, done: true}
// 第二次运行next()方法的时候不带参数,导致4*undefined等于NaN
const obj6 = fun7(2)
console.log(obj6.next()); //{value: 3, done: false}
console.log(obj6.next(2)); //{value: 2.6666666666666665, done: false}
console.log(obj6.next(3)); //{value: 13, done: true}
説明: next メソッドのパラメータは前の yield 式の戻り値を表すため、next メソッドを初めて使用するときはパラメータは必要ありません。v8 エンジンは next() メソッドの最初の使用を直接無視し、next() メソッドの 2 回目の使用のみが開始され、パラメーターは引き続き有効です。
9. for...of ループ
注: for...of ループは、実行時に Genrator 関数によって生成された Iterator オブジェクトを自動的にトラバースできるため、この時点で next() メソッドを呼び出す必要はなくなりました。
function* fun8() {
yield 1
yield 2
yield 3
return 4
}
for (let i of fun8()) {
console.log(i);
//1
//2
//3
}
注: 返されたオブジェクトの Done プロパティが true であるため、戻り値はトラバースされず、for...of ループは終了し、返されたオブジェクトは含まれません。
10.ジェネレーター.プロトタイプ.スロー
説明: Generator 関数によって返されるトラバーサー オブジェクトには、Generator 関数の本体でキャプチャできる throw メソッドを持つことができます。
const fun9 = function* () {
try {
yield
} catch (error) {
console.log("内部捕获", error);
}
}
const obj8 = fun9()
obj8.next()
try {
obj8.throw("错误1")
obj8.throw("错误2")
} catch (error) {
console.log("外部捕获", error);
}
//内部捕获 错误1
//外部捕获 错误2
説明: ジェネレーター関数内の catch ステートメントが実行されているため、このエラーは捕捉されず、ジェネレーター関数本体がスローされます。
11.ジェネレーター.プロトタイプ.リターン
説明: Generator 関数によって返される traverser 関数には、指定された値を返して Generator 関数を終了できる return メソッドもあります。
function* fun10() {
yield 1
yield 2
}
const obj10 = fun10()
console.log(obj10.next()); //{value: 1, done: false}
console.log(obj10.return(10));//{value: 10, done: true}
console.log(obj10.next()); //{value: undefined, done: true}
12.試してみてください...ついに
説明: try...finally コード ブロックを使用すると、try コード ブロックが実行され、return() メソッドがすぐにfinally コード ブロックに入り、実行後に関数全体が終了します。
function* fun11() {
try {
yield 1
yield 2
} finally {
yield 10
yield 20
}
}
const obj11 = fun11()
console.log(obj11.next()); //1
console.log(obj11.return(10)); //{value: 10, done: false}
console.log(obj11.next()); //{value: 20, done: false}
13. next()、throw()、return() 共通
説明: 実際、Generator 関数は機能すると実行を再開し、yield 式を別のステートメントに置き換えます。
14. 収量*式
説明: Generator 関数内で別の Generator 関数を実行する問題を解決します。
function* fun12() {
yield 2
yield 3
}
function* fun13() {
yield 4
yield* fun12()
yield 5
}
// 等价于
function* fun13() {
yield 4
yield 2
yield 3
yield 5
}
15. オブジェクトプロパティのジェネレータ関数
注: オブジェクトのプロパティがジェネレーター関数の場合、次の形式で省略できます。
const obj12 = {
*fun14() {
}
}
16.ジェネレーター機能の様子
説明: Generator 関数は常にトラバーサーを返すため、これは Generator 関数のインスタンスです。この点を変更するにはcallメソッドやapplyメソッドなどで変更できます。
function* fun15() {
this.a = 666
yield 1
}
const obj14 = {
}
const obj15 = fun15()
obj15.next()
console.log(obj15.a); //undefined
// 改变this
const obj16 = fun15.call(obj14)
console.log(obj16.next());//{value: 1, done: false}
console.log(obj14.a);
注: コンストラクターが呼び出された後、この空のオブジェクトは Generator 関数のインスタンス オブジェクトになります。