はじめに
まず、イテレーターとジェネレーターという言葉を耳にしたことはありますか?
自分はこの記事を書く数時間前に初めて知りました。。w
よく使うわけでは無いかもしれないですが、JavaScriptを理解する上で大事な概念だと思うので、この記事で概要や使い方を掴みましょう!
イテレータとは
イテレータとは、シーケンスおよび潜在的には終了時の戻り値を定義するオブジェクトのことです。具体的に言えば、2つのプロパティを持つオブジェクトを返すnext()
メソッドを持つことによってイテレータープロトコルを実装するオブジェクトです。
イテレーターを反復することを、消費する
と言います。(一般的に1回しか実行できないため)
- value
- イテレータを実行した際に際に返ってくる値
- done
- 処理が完了したかどうかの真偽値
イテレータ使用例
10になるまでループする処理をしてみます。
// イテレータを定義(初期値を設定することで無限ループを回避)
function genIterator(max = 10) {
let i = 0;
return {
next: function() {
if(i >= max) {
return {
done: true
}
} else {
return {
done: false,
value: i++
}
}
}
}
}
// イテレータを変数itに格納
const it = genIterator(10);
// next()メソッドを呼び出して、返り値を格納
let a = it.next();
// next()でtrueが返るまでループ
while(!a.done) {
console.log(a.value);
a = it.next();
}
以下のようにfor...of
を用いて短く記載することも可能です。(というかこの書き方の方が良い)
for...〇〇はいくつかあるので、混乱しないようにしましょう。
構文 | 内容 |
---|---|
for...of | 渡した値のvalueを取得 |
for...in | 渡した値のindexを取得 |
for...Each | 渡した値を一つずつ取り出すメソッド |
function genIterator(max = 10) {
...
}
// 値がイテレータを返すオブジェクトを生成
const obj = {
[Symbol.iterator]: genIterator.bind(null, 10)
}
// イテレータのnext()メソッドを実行して、trueが返るまでループする
for(const i of obj) {
console.log(i);
}
ジェネレータとは
イテレータを使いこなすとなると、複雑な部分が多く実装が少し難しいです。そこで、イテレータを簡単に実装する手段としてジェネレータを利用します。
ジェネレータ関数は、function* 構文
を使用して記述されます。
ジェネレータ使用例
// ジェネレータを定義(初期値を設定することで無限ループを回避)
function* genIterator(max = 10) {
let i = 0;
while(i < max) {
yield i++; // valueとdoneを返す
}
return;
}
// ジェネレータを変数itに格納
const it = genIterator(10);
// next()メソッドを呼び出して、返り値を格納
let a = it.next();
// next()でtrueが返るまでループ
while(!a.done) {
console.log(a.value);
a = it.next();
}
yield*
yield*
を用いると、渡した値を一つずつ取り出してくれます。
以下の例では、渡した配列の中身をnext()メソッドを呼び出すたびに取り出して返してくれます。
function* genIterator(){
yield* [1, 2, 3];
}
var it = genIterator();
console.log( it.next() ); // { value: 1, done: false }
console.log( it.next() ); // { value: 2, done: false }
console.log( it.next() ); // { value: 3, done: false }
console.log( it.next() ); // { value: undefined, done: true }
終わりに
最後になりますが、イテレータやジェネレータではnext()
メソッドを呼び出すまでは関数が実行されることはないので注意が必要ですね。しかし、ループ処理を簡単に実装できるのは嬉しい限りですね!
参考
[イテレーターとジェネレーター]
(https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Iterators_and_Generators)
[JavaScript の イテレータ を極める!]
(https://qiita.com/kura07/items/cf168a7ea20e8c2554c6#254-map-set-weakmap-weakset)
[JavaScript の ジェネレータ を極める!]
(https://qiita.com/kura07/items/d1a57ea64ef5c3de8528)