Iterables and Iterators:JavaScriptの詳細ガイド



この記事は、JavaScriptのイテラブルとイテレーターの詳細な紹介です。それを書くための私の主な動機は、ジェネレーターについて学ぶ準備をすることでした。実際、私は後でジェネレーターとReactフックを組み合わせて実験することを計画していました。興味があれば、私のTwitterまたは YouTubeをフォローして ください



実はジェネレーターの記事から始めようと思っていたのですが、イテラブルとイテレーターをよく理解しないと話せないことがすぐにわかりました。今からそれらに焦点を合わせます。私はあなたがこのトピックについて何も知らないと仮定しますが、同時にそれをかなり掘り下げます。だからあなたが何かなら iterablesとiteratorsについては知っていますが、それらを快適に使用できない場合は、この記事が役に立ちます。



前書き



お気づきのとおり、イテラブルイテレータについて説明 しています。これらは相互に関連していますが、概念が異なるため、記事を読むときは、特定のケースでどちらが議論されているかに注意してください。



反復可能なオブジェクトから始めましょう。それは何ですか?これは、次のように繰り返すことができます。



for (let element of iterable) {
    // do something with an element
}

      
      





ここではfor ... of



、ES6で導入されたループのみを確認していることに注意してください また、ループ for ... in



は古い構造であり、この記事ではまったく参照しません。



今、あなたは「さて、この反復可能な変数は単なる配列です!」と考えているかもしれません。そうです、配列は反復可能です。しかし、今では、ループで使用できるネイティブJavaScriptの他の構造があります for ... of



つまり、配列の他に、他の反復可能なオブジェクトがあります。



たとえばMap



、ES6で導入された反復が可能 です。



const ourMap = new Map();

ourMap.set(1, 'a');
ourMap.set(2, 'b');
ourMap.set(3, 'c');

for (let element of ourMap) {
    console.log(element);
}

      
      





このコードは次のように表示されます。



[1, 'a']
[2, 'b']
[3, 'c']

      
      





つまりelement



、各反復段階の変数は、 2つの要素の配列を格納します。 1つ目はキー、2つ目は値です。



ループを使用しfor ... of



反復できたことは、 が反復可能であるMap



ことを証明してい Map



ます。繰り返しますfor ... of



、ループ で使用できるの 反復可能なオブジェクトのみです。つまり、何かがこのループで機能する場合、それは反復可能なオブジェクトです。



コンストラクターがMap



オプションでキーと値のペアの反復可能オブジェクトを受け入れるのはおかしいです 。つまり、これは同じものを構築する別の方法です Map







const ourMap = new Map([
    [1, 'a'],
    [2, 'b'],
    [3, 'c'],
]);

      
      





また Map



、反復可能であるため、非常に簡単にコピーを作成できます。



const copyOfOurMap = new Map(ourMap);

      
      





Map



同じキーを同じ値で格納しますが、2つの異なる キーがあります。



したがって、反復可能なオブジェクトの2つの例(arrayとES6)を見ました Map



。しかし、彼らがどのようにして反復可能になる能力を獲得したのはまだわかりません 。答えは簡単ですそれらに関連付けられた反復子があり ます。注意:反復子 反復可能ではありません



イテレーターはイテラブルオブジェクトにどのように関連付けられていますか?単純に反復可能なオブジェクトには、そのプロパティに関数が含まれている必要があります Symbol.iterator



。呼び出されると、関数はこのオブジェクトのイテレーターを返す必要があります。



たとえば、配列イテレータを取得できます。



const ourArray = [1, 2, 3];

const iterator = ourArray[Symbol.iterator]();

console.log(iterator);

      
      





このコードはコンソールに出力され Object [Array Iterator] {}



ます。これで、配列に、ある種のオブジェクトであるイテレーターが関連付けられていることがわかりました。



イテレーターとは何ですか?



簡単だ。イテレーターは、メソッドを含むオブジェクト next



です。このメソッドが呼び出されると、次の値が返されます。



  • 一連の値の次の値。
  • イテレータが値の生成を終了したかどうかに関する情報。


next



配列イテレーターでメソッド呼び出して、これをテストしてみましょう



const result = iterator.next();

console.log(result);

      
      





コンソールにオブジェクトが表示されます { value: 1, done: false }



作成した配列の最初の要素は1で、ここでは値として表示されています。また、イテレーターがまだ終了していないという情報を受け取りました。つまり、関数next



呼び出して いくつかの値を取得できます。やってみよう!next



それをさらに2回呼びましょう



console.log(iterator.next());
console.log(iterator.next());

      
      





一つ一つを受けた { value: 2, done: false }



{ value: 3, done: false }







配列には3つの要素しかありません。もう一度呼び出すとどうなります next



か?



console.log(iterator.next());

      
      





今回はが表示され { value: undefined, done: true }



ます。これは、イテレーターが完了したことを示します。もう一度電話しても意味がありません next



これを行うと、何度も何度もオブジェクトを受け取ります { value: undefined, done: true }



done: true



繰り返しを停止することを意味します。



これfor ... of



で、内部で何が行われるかを理解できます



  • 最初のメソッド[Symbol.iterator]()



    は、イテレーターを取得するために呼び出されます。
  • メソッドnext



    は、取得するまでイテレーターで周期的に呼び出されますdone: true



  • 各呼び出しの後next



    、プロパティはループの本体で使用されますvalue





これをすべてコードで書いてみましょう。



const iterator = ourArray[Symbol.iterator]();

let result = iterator.next();

while (!result.done) {
    const element = result.value;

    // do some something with element

    result = iterator.next();
}

      
      





このコードはこれと同等です:



for (let element of ourArray) {
    // do something with element
}

      
      





これは、たとえば、console.log(element)



コメントの代わりに 挿入することで確認でき // do something with element



ます。



独自のイテレーターを作成する



これで、イテラブルとイテレーターが何であるかがわかりました。「自分のインスタンスを作成できますか?」という疑問が生じます。



もちろん!



イテレーターについては何も不思議なことはありません。これらはnext



、特別な方法で動作するメソッド持つ単なるオブジェクトです JSのどのネイティブ値が反復可能であるかはすでにわかっています。それらの中にオブジェクトは言及されていません。確かに、それらはネイティブに繰り返されません。次のようなオブジェクトについて考えてみます。



const ourObject = {
    1: 'a',
    2: 'b',
    3: 'c'
};

      
      





それを繰り返すと for (let element of ourObject)



、エラーが発生します object is not iterable







このようなオブジェクトを反復可能にして、独自の反復子を作成しましょう。



これを行うにObject



は、独自のメソッドでプロトタイプにパッチを適用する必要が あります [Symbol.iterator]()



プロトタイプにパッチを適用することは悪い習慣なので、以下を拡張して独自のクラスを作成しましょう Object







class IterableObject extends Object {
    constructor(object) {
        super();
        Object.assign(this, object);
    }
}

      
      





クラスのコンストラクターは、通常のオブジェクトを受け取り、そのプロパティを反復可能なオブジェクトにコピーします(ただし、実際にはまだ反復可能ではありません!)。



反復可能なオブジェクトを作成しましょう:



const iterableObject = new IterableObject({
    1: 'a',
    2: 'b',
    3: 'c'
})

      
      





クラスを IterableObject



本当に反復可能にするには、メソッドが必要 [Symbol.iterator]()



です。追加しましょう。



class IterableObject extends Object {
    constructor(object) {
        super();
        Object.assign(this, object);
    }

    [Symbol.iterator]() {

    }
}

      
      





これで、実際のイテレーターを作成できます。



メソッドを持つオブジェクトでなければならないことはすでにわかっています next



これから始めましょう。



class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        return {
            next() {}
        }
    }
}

      
      





各呼び出しの後に next



、ビューオブジェクトを返す必要があります { value, done }



架空の値で作りましょう。



class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        return {
            next() {
                return {
                    value: undefined,
                    done: false
                }
            }
        }
    }
}

      
      





このような反復可能なオブジェクトが与えられた場合:



const iterableObject = new IterableObject({
    1: 'a',
    2: 'b',
    3: 'c'
})

      
      





ES6の反復と同様に、キーと値のペアを出力します Map







['1', 'a']
['2', 'b']
['3', 'c']

      
      





イテレータでproperty



、値に配列を格納 します [key, valueForThatKey]



。これは、前の手順と比較した独自のソリューションであることに注意してください。キーのみまたはプロパティの値のみを返すイテレーターを作成したい場合は、問題なく実行できます。キーと値のペアを返すことにしました。



タイプの配列が必要 [key, valueForThatKey]



です。それを取得する最も簡単な方法は、メソッドを使用すること Object.entries



です。メソッドでイテレーターオブジェクトを作成する直前に使用できます [Symbol.iterator]()







class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        // we made an addition here
        const entries = Object.entries(this);

        return {
            next() {
                return {
                    value: undefined,
                    done: false
                }
            }
        }
    }
}

      
      





メソッドで返されるイテレーターは、JavaScriptクロージャーのおかげで変数にアクセスします entries







状態変数も必要です。次の呼び出しでどのキーと値のペアを返す必要があるかがわかります next



追加しましょう:



class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        const entries = Object.entries(this);
        // we made an addition here
        let index = 0;

        return {
            next() {
                return {
                    value: undefined,
                    done: false
                }
            }
        }
    }
}

      
      





呼び出しのたびに値を更新する予定であることがわかっているため 、変数index



c を宣言したことに注意してください これで、メソッドで実際の値を返す準備ができました let



next







next







class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        const entries = Object.entries(this);
        let index = 0;

        return {
            next() {
                return {
                    // we made a change here
                    value: entries[index],
                    done: false
                }
            }
        }
    }
}

      
      





簡単でした。変数entries



使用index



し、配列から正しいキーと値のペアにアクセスする だけ entries



です。



ここで、プロパティを処理する必要があり done



ますfalse



これは、常にであるため です。entries



とのほかにもう1つの変数を作成index



、呼び出しのたびに更新することができ ます next



。しかし、さらに簡単な方法があります。index



配列が範囲外 かどうかを確認しましょう entries







class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        const entries = Object.entries(this);
        let index = 0;

        return {
            next() {
                return {
                    value: entries[index],
                    // we made a change here
                    done: index >= entries.length
                }
            }
        }
    }
}

      
      





変数index



がその長さ以上になると 、イテレーターは終了します entries



。たとえば、yの entries



長さが3の場合、インデックス0、1、2の値が含まれます。また、変数 index



が3以上の場合は、値が残っていないことを意味します。終わったね。



このコードは ほとんど機能します。追加するものは1つだけ残っています。



変数index



は0から始まります が、...更新しません!それほど単純ではありません。を返した 、変数を更新する必要があります { value, done }



。しかし、私たちがそれを返したとき、メソッド next



式の後にコードがある場合でも、すぐに停止します return



しかし、我々は、オブジェクトを作成することができ { value, done }



、変数に格納し、それを更新し、 index



そして だけにして、オブジェクトを返します。



class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        const entries = Object.entries(this);
        let index = 0;

        return {
            next() {
                const result = {
                    value: entries[index],
                    done: index >= entries.length
                };

                index++;

                return result;
            }
        }
    }
}

      
      





変更後、クラス IterableObject



は次のようになります。



class IterableObject extends Object {
    constructor(object) {
        super();
        Object.assign(this, object);
    }

    [Symbol.iterator]() {
        const entries = Object.entries(this);
        let index = 0;

        return {
            next() {
                const result = {
                    value: entries[index],
                    done: index >= entries.length
                };

                index++;

                return result;
            }
        }
    }
}

      
      





コードはうまく機能しますが、かなり混乱しました。これはindex



オブジェクトの作成 に更新するためのよりスマートでありながらわかりにくい方法を示しているため result



です。index



-1に初期化できます !また、からオブジェクトを返す前に更新されますが next



、最初の更新では-1が0に置き換えられるため、すべて正常に機能します。



それでは、次のようにします。



class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        const entries = Object.entries(this);
        let index = -1;

        return {
            next() {
                index++;

                return {
                    value: entries[index],
                    done: index >= entries.length
                }
            }
        }
    }
}

      
      





ご覧のとおり、オブジェクトの作成result



と更新の 順序を調整する必要はありません index



2回目の呼び出しでは、 index



1に更新され、別の結果が返されます。以下同様です。すべてが希望どおりに機能し、コードははるかに単純に見えます。



しかし、どうすれば作業の正確さを確認できますか?メソッド[Symbol.iterator]()



手動で実行して イテレーターをインスタンス化し、呼び出しの結果を直接確認できます next



しかし、あなたははるかに簡単に行うことができます!反復可能なオブジェクトはループに挿入できると前述しました for ... of



途中で反復可能なオブジェクトによって返された値をログに記録して、それを実行しましょう:



const iterableObject = new IterableObject({
    1: 'a',
    2: 'b',
    3: 'c'
});

for (let element of iterableObject) {
    console.log(element);
}

      
      





動作します!これは、コンソールに表示されるものです。



[ '1', 'a' ]
[ '2', 'b' ]
[ '3', 'c' ]

      
      





涼しい!for ... of



組み込みのイテレーターがネイティブに含まれていないため、ループ使用できないオブジェクトから始めました 。しかし、我々は我々自身が作成し IterableObject



た、 持っている関連する自己書かれたイテレータを。



iterablesとiteratorsの可能性をご覧いただければ幸いです。これは、ループfor ... of



などのJS関数を操作するための独自のデータ構造を作成できるメカニズムであり、ネイティブ構造と同じように機能します 。これは非常に便利な機能であり、特定の状況で、特にデータ構造を頻繁に繰り返す場合に、コードを大幅に簡素化できます。



さらに、これらの反復が返すものを正確にカスタマイズできます。イテレーターはキーと値のペアを返すようになりました。値のみが必要な場合はどうなりますか?簡単です。イテレーターを書き直すだけです。



class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        // changed `entries` to `values`
        const values = Object.values(this);
        let index = -1;

        return {
            next() {
                index++;

                return {
                    // changed `entries` to `values`
                    value: values[index],
                    // changed `entries` to `values`
                    done: index >= values.length
                }
            }
        }
    }
}

      
      





以上です!ここでループを開始する for ... of



と、コンソールに次のように表示されます。



a
b
c

      
      





オブジェクトの値のみを返しました。これらすべてが、自作の反復子の柔軟性を証明しています。あなたは彼らにあなたが望むものを何でも返させることができます。



...反復可能なオブジェクトとしての反復子



反復子と反復可能オブジェクトを混同することは非常に一般的です。これは間違いであり、私は2つをきちんと分離しようとしました。人々が頻繁に混乱させる理由を私は知っていると思います。



反復子は...時々反復可能であることが判明しました!



これは何を意味するのでしょうか?ご存知のように、イテラブルはイテレータが関連付けられているオブジェクトです。すべてのネイティブJavaScriptイテレーターには、[Symbol.iterator]()



別のイテレーターを返すメソッド があります。これにより、最初のイテレーターがイテラブルオブジェクトになります。



配列から返されたイテレーターを取得して呼び出すと、これを確認できます [Symbol.iterator]()







const ourArray = [1, 2, 3];

const iterator = ourArray[Symbol.iterator]();

const secondIterator = iterator[Symbol.iterator]();

console.log(secondIterator);

      
      





このコードを実行すると、が表示されます Object [Array Iterator] {}



。つまり、イテレーターには、それに関連付けられた別のイテレーターが含まれているだけでなく、配列でもあります。



両方のイテレーターをと比較すると、 ===,



まったく同じであることがわかります。



const iterator = ourArray[Symbol.iterator]();

const secondIterator = iterator[Symbol.iterator]();

// logs `true`
console.log(iterator === secondIterator);

      
      





最初は、それ自体のイテレーターであるイテレーターの動作がおかしいと感じるかもしれません。しかし、これは非常に便利な機能です。ネイキッドイテレーターをループfor ... of



固定することはできません。イテレーター オブジェクト(メソッドを持つオブジェクト)のみを受け入れます [Symbol.iterator]()







ただし、イテレーターがそれ自体のイテレーター(したがってイテラブルオブジェクト)である状況では、問題が隠されます。ネイティブJSイテレーターにはメソッドが含まれているため [Symbol.iterator]()



、何も考えずに直接ループに渡すことができます for ... of







その結果、このスニペットは次のようになります。



const ourArray = [1, 2, 3];

for (let element of ourArray) {
    console.log(element);
}

      
      





そしてこれ:



const ourArray = [1, 2, 3];
const iterator = ourArray[Symbol.iterator]();

for (let element of iterator) {
    console.log(element);
}

      
      





シームレスに動作し、同じことを行います。しかし、なぜ誰かがこのようなイテレーターをループで直接使用するの for ... of



でしょうか?時にはそれは避けられないことです。



まず、イテラブルに属さずにイテレータを作成する必要がある場合があります。以下でこの例を見ていきますが、それは珍しいことではありません。反復可能自体が必要ない場合もあります。



そして、裸のイテレーターを持っていることがあなたがそれをで使うことができないことを意味するならば、それは非常に厄介でしょう for ... of



。もちろん、これはメソッドnext



やループなど を使用して手動で行うことができますが while



、これには多くのコードを記述しなければならず、さらに繰り返しを行う必要があることがわかりました。



解決策は簡単です。定型コードを避けてループfor ... of



イテレーターを使用する 場合は、イテレーターをイテラブルオブジェクトにする必要があります。



一方、[Symbol.iterator]()



以外のメソッドからイテレータを取得することもよくあり ます。例えば、ES6は、 Map



メソッドが含まれ entries



values



そして keys



。それらはすべてイテレーターを返します。



ネイティブJSイテレーターもイテラブルオブジェクトでない場合for ... of



、次のように、これらのメソッドをループ直接使用することはできません



for (let element of map.entries()) {
    console.log(element);
}

for (let element of map.values()) {
    console.log(element);
}

for (let element of map.keys()) {
    console.log(element);
}

      
      





メソッドによって返されるイテレーターも反復可能なオブジェクトであるため、このコードは機能します。それ以外の場合は、たとえば、呼び出し結果map.entries()



を愚かな反復可能なオブジェクトにラップする必要があり ます。幸い、これを行う必要はありません。



独自の反復可能なオブジェクトを作成することをお勧めします。特に、[Symbol.iterator]()



以外のメソッドから返された場合 。イテレーターをイテラブルオブジェクトにするのは簡単です。イテレーターの例を示しましょう IterableObject







class IterableObject extends Object {
    // same as before

    [Symbol.iterator]() {
        // same as before

        return {
            next() {
                // same as before
            },

            [Symbol.iterator]() {
                return this;
            }
        }
    }
}

      
      





メソッドの[Symbol.iterator]()



下にメソッド を作成しました next



this



返すだけで、このイテレーターを独自のイテレーターにしました。つまり、自分自身を 返します。上記では、アレイイテレータがどのように動作するかをすでに見てきました。これは、イテレーターがfor ... of



直接ループ動作するのに十分です



イテレーター状態



これで、各イテレーターに状態が関連付けられていることは明らかです。たとえば、イテレーターで IterableObject



は、状態(変数)をindex



クロージャーとして格納しました そして、各反復ステップの後にそれを更新しました。



反復プロセスが完了した後はどうなりますか?イテレーターは役に立たなくなり、削除できます(すべきです!)。ネイティブJSオブジェクトの例でもこれが発生していることがわかります。配列イテレーターを使用して、ループ内で2回実行してみましょう for ... of







const ourArray = [1, 2, 3];

const iterator = ourArray[Symbol.iterator]();

for (let element of iterator) {
    console.log(element);
}

for (let element of iterator) {
    console.log(element);
}

      
      





あなたは二度番号を表示するには、コンソールを期待するかもしれない 1



2



3



しかし、結果は次のようになります。



1
2
3

      
      





どうして? ループが終了した後、



手動で呼び出しましょう next







const ourArray = [1, 2, 3];

const iterator = ourArray[Symbol.iterator]();

for (let element of iterator) {
    console.log(element);
}

console.log(iterator.next());

      
      





最後のログがコンソールに出力されます { value: undefined, done: true }







それでおしまい。ループの終了後、イテレーターは「完了」状態になります。これで、常にオブジェクトが返されます { value: undefined, done: true }







イテレーターの状態を「リセット」して、で2回使用できるようにする方法はあり for ... of



ますか?場合によっては可能ですが、意味がありません。したがって、これ [Symbol.iterator]



は単なるプロパティではなく、メソッドです。メソッドを再度呼び出して、別のイテレーターを取得でき ます。



const ourArray = [1, 2, 3];

const iterator = ourArray[Symbol.iterator]();

for (let element of iterator) {
    console.log(element);
}

const secondIterator = ourArray[Symbol.iterator]();

for (let element of secondIterator) {
    console.log(element);
}

      
      





すべてが期待どおりに機能するようになりました。アレイを介した複数の順方向ループが機能する理由を見てみましょう。



const ourArray = [1, 2, 3];

for (let element of ourArray) {
    console.log(element);
}

for (let element of ourArray) {
    console.log(element);
}

      
      





すべてのループ for ... of



異なるイテレーターを使用し ます!イテレーターとループが終了すると、このイテレーターは使用されなくなります。



イテレーターとアレイ



ループfor ... of



(間接的ではありますが)イテレーターを使用するため、イテレーター は一見配列のように見えます。しかし、2つの重要な違いがあります。 IteratorとArrayは、貪欲で怠惰な値の概念を使用します。配列を作成すると、任意の時点で特定の長さがあり、その値はすでに初期化されています。もちろん、値をまったく含まない配列を作成することもできますが、そうではありません。私のポイントは、値を書き込んでアクセスした 後にのみ値を初期化する配列を作成することはできないということです array[someIndex]



。プロキシやその他のトリックでこれを回避することは可能かもしれませんが、デフォルトではJavaScript配列はそのように動作しません。



そして、彼らが配列に長さがあると言うとき、彼らはこの長さが有限であることを意味します。 JavaScriptには無限の配列はありません。



これらの2つの品質はアレイ貪欲さを示して ます。



そして、反復子は 怠惰です。



これを示すために、2つのイテレーターを作成します。1つ目は有限配列とは異なり無限であり、2つ目はイテレーターユーザーから要求された場合にのみ値を初期化します。



無限のイテレーターから始めましょう。威圧的に聞こえますが、作成は非常に簡単です。イテレーターは0から始まり、各ステップでシーケンス内の次の番号を返します。永遠に。



const counterIterator = {
    integer: -1,

    next() {
        this.integer++;
        return { value: this.integer, done: false };
    },

    [Symbol.iterator]() {
        return this;
    }
}

      
      





以上です!integer



-1のプロパティから始めました 。呼び出しごと next



に、1ずつインクリメントし、オブジェクトにとして返します value



。前述のトリックを再度使用したことに注意してください。最初に0を返すために-1から開始しました。



また、プロパティも確認してください done



。それ 常に偽です。このイテレーターは終わりません!



さらに、単純な実装を与えることで、イテレーターをイテラブルにしました [Symbol.iterator]()







最後にもう1つ、これは前述のケースです。イテレーターを作成しましたが、イテレーターの親が機能する必要はありません。



それでは、このイテレーターをループで試してみましょう for ... of



ある時点でループを停止することを覚えておく必要があります。そうしないと、コードが永久に実行されます。



for (let element of counterIterator) {
    if (element > 5) {
        break;
    }
    
    console.log(element);
}

      
      





起動後、コンソールに次のように表示されます。



0
1
2
3
4
5

      
      





実際には、必要な数の数値を返す無限のイテレーターを作成しました。そして、それを作るのはとても簡単でした!



次に、要求されるまで値を作成しないイテレーターを作成しましょう。



ええと...私たちはすでにそれをしました! 一度に1つのプロパティ番号しか保存さ



れないことに気づきました か?これは、通話で返される最後の番号 です。そして、これは同じ怠惰です。イテレーターは、任意の数(より正確には、正の整数)を返す可能性があります 。ただし、必要な場合、つまりメソッドが呼び出された場合にのみ作成され ます。 counterIterator



integer



next



next







それはかなりギミックに見えるかもしれません。結局のところ、数値はすばやく作成され、多くのメモリスペースを占有しません。ただし、大量のメモリを使用する非常に大きなオブジェクトを操作している場合は、配列をイテレータに置き換えると、プログラムが高速化され、メモリが節約される場合があります。



オブジェクトが大きいほど(または作成に時間がかかるほど)、メリットは大きくなります。



イテレーターを使用する他の方法



これまでのところ、ループ内で、for ... of



またはを使用して手動で 反復子を消費しただけ next



です。しかし、これらが唯一の方法ではありません。



コンストラクターMap



が反復可能オブジェクトを引数として受け取ることはすでに見てき ました。メソッドを使用してArray.from



、反復可能オブジェクトを配列に簡単に変換することも できます。しかし、注意してください!私が言ったように、イテレーターの怠惰は時々大きな利点になることがあります。配列に変換すると、遅延がなくなります。イテレーターによって返されるすべての値はすぐに初期化されてから、配列に配置されます。これは、無限counterIterator



を配列に変換しようとすると、災害につながることを意味し ます。 Array.from



結果を返さずに永久に実行されます。したがって、iterable / iteratorを配列に変換する前に、操作が安全であることを確認する必要があります。



興味深いことに、iterablesはspread演算子でもうまく機能し (...



ます。)Array.from



すべてのイテレーター値が一度に生成される場合、これは同じように機能することを忘れないでください たとえば、spread演算子を使用して独自のバージョンを作成できます Array.from



演算子をiterableに適用してから、値を配列に配置するだけです:



const arrayFromIterator = [...iterable];

      
      





iterableからすべての値を取得して関数に適用することもできます:



someFunction(...iterable);

      
      





結論



私はあなたが今、物品のIterableオブジェクトのタイトル理解してほしい イテレータを。それらが何であるか、それらがどのように異なるか、それらを使用する方法、および独自のインスタンスを作成する方法を学びました。これで、ジェネレーターを使用する準備が完全に整いました。イテレーターに精通している場合は、次のトピックに進むのはそれほど難しくありません。



All Articles