generatorメモ
generatorとは 何回も入ったり出たりできる関数 generator内でyieldを使うたびに一度関数の外へ出て、 再度generator関数を呼ぶと抜けた箇所から処理を始める事のできる関数
宣言の仕方
function* 関数名 or function *関数名
のようにして書く
具体的な使い方
function* Shopping(item){ yield item.meat; yield item.vegetables; yield item.fish; } //店関連の世界 const Items = { meat:'肉', vegetables:'野菜', fish:'魚' }; const basket = []; for(let item of Shopping(Items)){ basket.push(item); } basket;//["肉","野菜","魚"]
委譲するやり方 ジェネレーター内で、別のジェネレーターをyield* の形で記載すると、 別のジェネレーター内のyieldの探索を始めることができる これを委譲という
function* TeamIterator(team){ yield team.lead; yield team.manager; yield team.engineer; const testingTeamGenerator = TestingTeamIterator(team.testingTeam); yield* testingTeamGenerator; } function* TestingTeamIterator(team){ yield team.lead; yield team.tester; } const testingTeam ={ lead: 'テスト花子', tester:'テスト太郎' } const engineeringTeam = { lead: '開発太郎', manager: '開発花子', engineer:'開発一郎', testingTeam }; const names = []; for(let name of TeamIterator(engineeringTeam)){ names.push(name); } names;//開発太郎","開発花子","開発一郎","テスト花子","テスト太郎"]
ただこれだとコードがめちゃくちゃ読みにくいので Symbol.iteratorを使って読みやすくする 下記コードでは、[Symbol.iterator]を使って各オブジェクト内でジェネレーターを宣言し、 for...ofではengineeringTeam内のSymbol.iteratorを検索、
yield* team.testingTeam;ではtestingTeamのSymbol.iteratorを検索 している為上記と同じ動作になる
const testingTeam = { lead: 'テスト花子', tester: 'テスト太郎', [Symbol.iterator]: function* () { yield this.lead; yield this.tester; } } const engineeringTeam = { testingTeam, lead: '開発太郎', manager: '開発花子', engineer:'開発一郎', [Symbol.iterator]:function*(){ yield this.lead; yield this.manager; yield this.engineer; yield* this.testingTeam; } }; const names = []; for(let name of engineeringTeam){ names.push(name); } names;//開発太郎","開発花子","開発一郎","テスト花子","テスト太郎"]
[Symbol.iterator]のように書いてプロパティを追加することを動的プロパティという 動的プロパティに関してはこっち
classで使う場合 下記コードは、1つのコメントに3つのコメントがついている そのコメントを全て出力したい時にジェネレーターを使って検索させるというコード
class Comment{ constructor(content,children){ this.content = content; this.children = children; } *[Symbol.iterator](){ yield this.content; for(let child of this.children){//childに対して検索を行う(全てのコメントを出す) yield* child; } } } const children = [ new Comment('1-1',[new Comment('1-1-1', [])]), new Comment('1-2',[new Comment('1-2-1', [])]), new Comment('1-3',[new Comment('1-3-1', [])]) ]; const tree = new Comment('1',children); const values = []; for(let value of tree){ values.push(value); } values;//["1","1-1","1-1-1","1-2","1-2-1","1-3","1-3-1"]