反復とは、データセットから特定の順序でデータを継続的に抽出するプロセスを指します。
それでは、反復と走査の違いは何でしょうか?
では、イテレータは、反復を実装するためにnext
メソッドを呼び出すことができるオブジェクトです。 2 つのプロパティを持つオブジェクトを返します。
value
: 反復可能オブジェクトの次の値done
: すべてのデータが取得されたかどうかを示します。 false
まだデータが存在することを意味し、 true
その後データが存在しないことを意味します。、反復可能オブジェクト内のイテレータ ファクトリ関数Symbol.iterator
を通じてイテレータを生成するためにのみ
const arr = []console.log(arr)
const arr = [1, 2, 3] const iter1 = arr[Symbol.iterator]() // イテレータ ファクトリ関数 `Symbol.iterator` を通じてイテレータを生成します。 コンソールログ(iter1) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log('%c%s', 'color:red;font-size:24px;', '================') const mymap = new Map() mymap.set('名前', 'clz') mymap.set('年齢', 21) const iter2 = mymap[Symbol.iterator]() // イテレータ ファクトリ関数 `Symbol.iterator` を通じてイテレータを生成します。 コンソール.ログ(iter2) console.log(iter2.next()) console.log(iter2.next()) console.log(iter2.next())
最後の値を取得した後、つまり、反復子の次のvalue
がundefined
なったときに、反復子が完了したことがわかります。
ただし、上記のステートメントはあまり正確ではありません。イテレータの次のvalue
がundefined
の場合、このステートメントは完了しません。また、実際に値が存在しないのか、それとも反復可能オブジェクトにundefined
値が存在するのかを判断する必要もあります。反復可能オブジェクト内にundefined
値がある場合、この時点では完了しません。
const arr = [1、2、3、未定義] const iter1 = arr[Symbol.iterator]() // イテレータ ファクトリ関数 `Symbol.iterator` を通じてイテレータを生成します。 コンソールログ(iter1) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next())
互いに干渉することなくイテレータ ファクトリ関数を複数回呼び出して、複数のイテレータを生成できます。各イテレータは、反復可能なオブジェクトの 1 回限りの順序付けられた走査を表します。異なる反復子は互いに干渉せず、反復可能なオブジェクトのみを独立して走査します。
const arr = [1, 2, 3] const iter1 = arr[Symbol.iterator]() // イテレータ ファクトリ関数 `Symbol.iterator` を通じてイテレータを生成します。 const iter2 = arr[Symbol.iterator]() console.log('Iterator1:', iter1.next()) console.log('Iterator2:', iter2.next()) console.log('Iterator1:', iter1.next()) console.log('Iterator2:', iter2.next())
const arr = [1, 2, 3] const iter = arr[Symbol.iterator]() for (iter の const i) { console.log(i) // 1、2、3を順番に出力します反復子
は
反復中に反復可能オブジェクトが変更されると、反復子によって得られる結果も変更されます。
const arr = [1, 2, 3] コンソール.ログ(arr) const iter = arr[Symbol.iterator]() console.log(iter.next()) arr[1] = 999 console.log(iter.next()) console.log(iter.next())
done: true
を繰り返すと、 next
呼び出すときにエラーが報告されますか、それとも何も返されませんか?
ただし、いいえ、イテレータは完了しましたが、完了していない状態になります。done done: true
完了したが、今後もnext
を呼び出すことができることを意味します。ただし、結果は常に{ value: undefined, done: true }
になります。 。だからこそ、 「やっているようでやっていない」と言われているのです。
const arr = [1, 2, 3] const iter = arr[Symbol.iterator]() console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next())
上記の例から、反復子は反復子ファクトリー関数Symbol.iterator
を通じて生成されることがわかります。そのため、反復子反復子ファクトリー関数を実装する必要があります。その後、反復子はnext
ことも行う必要があります。 next
メソッドを実装します。イテレータ ファクトリ関数に関しては、実際にはインスタンスthis
直接返します。
カウンタの例:
class Counter { コンストラクター(制限) { this.count = 1 this.limit = 制限 } 次() { if (this.count <= this.limit) { 戻る { 完了: false、 値: this.count++ } } それ以外 { return { 完了: true、値: 未定義 } } } [Symbol.iterator]() { これを返す }}
const カウンタ = 新しいカウンタ(3) const iter = counter[Symbol.iterator]() console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next())
一見すると問題はありませんが、 for-of
使ってトラバースしてみると問題が見つかります。
const counter = new Counter(3)for (カウンターを i にします) { console.log(i)}console.log('別の反復:')for (カウンターの i を許可) { コンソール.ログ(i)}
for-of
ループを使用すると、ループが使い捨て可能になります。これは、 count
このインスタンスの変数であるため、両方の反復で同じ変数が使用されるためです。ただし、変数の最初のループの後、制限を超えているため、 for-of
ループを使用しても何も取得されません。結果はまたそうでした。
count
変数をクロージャに配置し、クロージャを介してイテレータを返すと、作成された各イテレータが新しいカウンタに対応するようになります。
クラス カウンタ { コンストラクター(制限) { this.limit = 制限 } [Symbol.iterator]() { カウント = 1 にします const 制限 = this.limit return { // 反復は実際には next メソッド next() を呼び出すことによって実装されるため、イテレータ ファクトリ関数は next メソッドを持つオブジェクトを返す必要があります。 { if (カウント <= 制限) { 戻る { 完了: false、 値: count++ } } それ以外 { return { 完了: true、値: 未定義 } } } } }}
テスト
const counter = new Counter(3)for (カウンターを i にします) { console.log(i)}console.log('別の反復:')for (カウンターの i を許可) { コンソール.ログ(i)}
return
for-of
ループを使用するのと同じです。イテレータが早期に終了すると、 next
メソッドも呼び出されます。
[Symbol.iterator]() { カウント = 1 にします const 制限 = this.limit return { // 反復は実際には next メソッド next() を呼び出すことによって実装されるため、イテレータ ファクトリ関数は next メソッドを持つオブジェクトを返す必要があります。 { if (カウント <= 制限) { 戻る { 完了: false、 値: count++ } } それ以外 { return { 完了: true、値: 未定義 } } }、 戻る() { console.log('反復子の早期終了') 戻り値 { 完了: true } } }}
テスト
const counter = new Counter(5)for (カウンターを i にします) { if (i === 3) { 壊す; } コンソール.ログ(i)}
イテレータが閉じていない場合は、中断したところから繰り返しを続行できます。配列イテレータを閉じることはできません。
const arr = [1, 2, 3, 4, 5]const iter = arr[Symbol.iterator]()iter.return = function () { console.log('反復子を早期に終了します') 戻る { 完了: true }}for (iter の const i) { コンソール.ログ(i) if (i === 2) { 壊す }}for (iter の const i) { コンソール.ログ(i)}