ES6:ジェネレーターの詳細
概要
-
ジェネレーター関数は、ES6が提供する非同期プログラミングソリューションです。これは、複数の内部状態をカプセル化するステートマシンとして理解できます。-
-
Generator関数を実行すると、トラバーサーオブジェクトが返されます。トラバーサーオブジェクトは、関数内の各状態を順番にトラバースできます。
-
ジェネレーター機能には2つの特徴があります。
- 関数と関数名の間にはアスタリスクがあります。
- さまざまな内部状態を定義するために、yieldステートメントが関数本体内で使用されます。
-
例:
function*helloWorldGenerator(){ yield '听不见!'; yield '重来!'; return '很有精神!' } let hw = helloWorldGenerator(); hw.next(); // { value : '听不见!',done : false } hw.next(); // { value : '重来!',done : false } hw.next(); // { value : '很有精神!',done : true } hw.next(); // { value : undefined , done : true }
-
この機能を使用すると、関数の非同期プログラミングメカニズムを実現できます。
降伏式
-
トラバーサーの次のメソッドの実行メカニズムは次のとおりです。
- yieldステートメントが発生すると、次の操作の実行が一時停止され、yield式の値が返されたオブジェクトのvalue属性値として返されます。
- 次回、次のyieldステートメントが検出されるまで、実行を継続するために次の呼び出しが呼び出されたとき。
- 歩留まりがない場合は、returnステートメントに直接実行します。
- returnステートメントがない場合、値が未定義のオブジェクトが返されます。
-
利回りは、使用する前にジェネレーター関数に配置する必要があります。
-
別の式でyieldを使用する場合は、括弧を追加する必要があります。
console.log('hello' + yield 123); ///error console.log('hello' + (yield 123)); //ok
次のメソッドのパラメーター
-
次のメソッドは、前のステートメントの戻り値として使用されるパラメーターを受け取ることができます。nextにパラメーターがない場合、undefinedを返します。
function* f(){ for(let i=0;ture;i++){ let reset = yield i; if(reset){ i = -1; } } } let g = f(); g.next() //{value : 0,done : false}; g.next() //{value : 1,done : false}; g.next(true) //{value : 0,done : false};
for ... ofメソッド
-
for ... ofループは、Generator関数によって生成されたIteratorオブジェクトを自動的にトラバースできるため、次のメソッドを使用する必要がなくなります。
function* foo(){ yield 1; yield 2; yield 3; yield 4; yield 5; } for (let v of foo()){ console.log(v); }
収量*式
-
ジェネレーターで別のジェネレーター関数を呼び出す場合、デフォルトは効果がありません。
function* foo(){ yield 'a'; yield 'b'; } function bar(){ yield 1; foo(); yield 2; } for(let i of bar()){ console.log(i); } >>1 >>2
-
直接呼び出しはfor ... of;でfoo()を実行できないことがわかります。
-
このとき、yield *ステートメントを使用する必要があるため、上記のコードは次のように変更できます。
function* foo(){ yield 'a'; yield 'b'; } function bar(){ yield 1; yield* foo(); yield 2; } for(let i of bar()){ console.log(i); } >>1 >>'a' >>'b' >>2
-
yield *の後に配列が続く場合、配列のメンバーがトラバースされます。
function* foo(){ yield [1,2,3,4,5]; } foo().next(); //[1,2,3,4,5] function* foo(){ yield* [1,2,3,4,5]; } foo().next(); //{value : 1,done : false}
-
yield *式は、ネストされた配列のすべてのメンバーをすばやくトラバースできます。
function* iterTree(tree){ if(Array.isArray(tree)){ for(let i=0;i<tree.length;i++); yield* iterTree(tree[i]); }else{ yield tree; } } const tree = [1,[2,3],[4,5]]; for(let x of iterTree(tree)){ console.log(x); } >> 1 >> 2 >> 3 >> 4 >> 5
これはジェネレーター機能です
-
Generator関数によって返されるイテレータは、元のGenerator関数のインスタンスであり、元の関数のプロトタイプも継承します。
-
したがって、Generator関数のイテレータは、元の関数のプロパティに直接アクセスできません。
function* foo(){ this.a = 1; } let obj = foo(); console.log(obj.a); //undefined
-
元の関数のプロパティを取得するには、柔軟なメソッドを使用して取得できます。callメソッドを使用して、これをGenerator関数内にバインドします。
function* foo(){ this.a = 1; yield this.b = 2; yield this.c = 3; } let obj = { }; let bar = foo.call(obj); bar.next(); //{value : 2 , done : false}; bar.next(); //{value : 3 , done : false}; console.log(obj.a) // 1 console.log(obj.b) // 2 console.log(obj.c) // 3