【ECMAScript2015(ES6)】ES6の「Generators(ジェネレーター)とIterator(イテレータ)」をしばく!

【ECMAScript2015(ES6)】後で猫に教えてあげたいES6の「Generators(ジェネレーター)とIterator(イテレータ)」

昨日はSymbol(シンボル)でしたが、今日はGeneratorsとIterator。
babel立ち上げてコード確認しながらやりました。

ジェネレータってなにかって再帰処理を簡単にしてくれるものなんですね。
そのイテレータオブジェクトを返す関数がジェネレータ

ジェネレータを扱うにはイテレータを理解する必要があるようです。

イテレータを理解する

イテラタブルなオブジェクト・・・イテレータを返すオブジェクト
イテラブルなオブジェクトとは以下です

  • Array
  • String
  • Iterator
  • ジェネレータ関数から生成されるジェネレータ
  • argument
  • Map
  • Set
  • TypedArray(型付き配列みたいです。わからないのでこんどまとめます)

ArrayとStringってイテレータブルだったのかと思って
["a","b"].next();やってもだめですよ。
それには
["a","b"][Symbole.iterator]();
としてIteratorをつくります。

Iteration protocols

StringとArrayがイテラブルなオブジェクトであることを確認する

イテレータ・・・イテレーティブリザルトを返すオブジェクト。nextメソッドを持つ
イテレーティブリザルト・・・valueとdoneプロパティをもつこのような{value: 1, done: false}オブジェクト

自作イテラブルなオブジェクト
[code lang="javascript"]
var obj = {}; // イテラブルなオブジェクト
obj[Symbol.iterator] = function(){//イテレータを返す関数を代入
var iterator = {}; // イテレータ
var num = 1;
iterator.next = function(){//next実行してリザルトを返す関数を代入
var iteratorResult = (num <= 10)
? { value: num++, done: false }
: { value: undefined, done: true };
return iteratorResult; // イテレータリザルトを返す
};
return iterator;//イテレータを返す
};
[/code]

実際に下の様に値を動かします

今回のコード

[code lang="javascript"]
console.log("実験1")
var arry = [4, 3, 2];
for(var i of arry) console.log(i)
//for/ofはイテレータオブジェクトのdoneがfalseの間next()を実行してvalueを渡す
//4
//3
//2

//for ofの処理は
//1 iteratorオブジェクトからイテレータを取り出す
//2 イテレータのnextメソッドでイテレータリザルトを取り出す
//3 イテレータリザルトのdoneプロパティがfalseならconsole.log(i)を実行する
//4 以後nextを実行、done === trueになるまで繰り返す

<h4>ジェネレータを作成して値を動かす</h4>

ジェネレータとはイテレータを返す関数を簡単に書くもの。

console.log(`

${'実験3'}

`);
//簡単な説明
//1・ジェネレーター関数を作成
function* gf(){
yield 1 //イールドというみたいです「支払う」意味
yield 2
}

//2・ジェネレータを作成
const g = gf();//Iteratorを取得

//3・イテレータリザルトを取得

//方法1
//ジェネレータが持つnextメソッドを利用
console.log(g.next())//{"value":1,"done":false}
console.log(g.next())//{"value":2,"done":false}
console.log(g.next())//{"done":true}

//NOTE
//イテレータリザルト
//{"value":1,"done":false}
//こちらのdoneがfalseの場合valueが返る→処理される
//{"done":true}
//とされイテレータ処理するものがないことが確認される

//方法2
//for/ofでいっぺんに処理する。next処理がされる
for(var v of g) console.log(v);//イテレータを渡している
//1
//2

//ジェネレータ自体がイテラブルオブジェクトなのでこのままわたしてもok
//for(var v of gf()) console.log(v)

/////////////////////////////
console.log(`

${'実験4'}

`);

//一回目の処理と二回目の戻り値を変える

function* gfu2(n){
n++
yield n
n *= 3//2回目の処理ではここから始まり、nは1回目の処理が終わっている(5が代入されている)
yield n//15を返す
}

const gg = gfu2(4);
console.log("実験4-1",gg.next().value);//1回目の実行
//実験4-1 5
console.log("実験4-2",gg.next().value);//2回目の実行
//実験4-2 15

/////////////////////////////
console.log(`

${'実験5'}

`);

//1~20迄を出力する
function* gfu3(from, to){
while (from <= to) yield from++
}

for(var i of gfu3(1, 10)){
console.log(i);
}

/////////////////////////////
console.log(`

${'実験6'}

`);
//呼び出し側の値を受け取る
function* gfu4(){
var num = yield [10,20,30]//numは2回目next()実行時の仮引数になる
var num2 = yield 1 + num//num2は3回目next()実行時の仮引数になる
yield 2 + num2
yield num + num2
}

var g4 = gfu4();
console.log("実験6-1",g4.next().value);
//実験2-1 [10,20,30]
console.log("実験6-2",g4.next(4).value);//値を渡す
//実験2-2 5
console.log("実験6-3",g4.next(10).value);
//実験2-3 12
console.log("実験6-4",g4.next().value);
//実験2-4 14

/////////////////////////////
console.log(`

${'Tips'}

`);
//もしfor/of中にindexがほしいならforEach
//もしくはentries()
const arry3 = ["one", "two", "three"]
for(const [key, value] of arry3.entries()) {
console.log(key, value);
}
//0 one
//1 two
//2 three

//またはArray.indexOf();
const arry4 = ["one", "two", "three"]
for(const i of arry4) {
console.log(i);
console.log(arry4.indexOf(i));
}
//"one"
//0
//"two"
//1
//"three"
//2

/////////////////////////////
console.log(`

${'実験7'}

`);

function* gfun6(){
yield "mo"
yield* ["ri","ta"]
}
const g6 = gfun6();
console.log(g6.next().value);//mo
console.log(g6.next().value);//ri
console.log(g6.next().value);//ta

/////////////////////////////
//【WIP】疲れた。。。休憩します

console.log([...gfun6()]);

/////////////////////////////
[/code]

別の実験コード

参照1
参照2

javascript記事
フロントエンド記事
ある日僕は猫にJAVASCRIPTを教えることになった