Object.entries を使用して、それがどのように機能するか疑問に思ったことはありますか?思っているよりもずっと簡単です!
基本的な実装は次のとおりです。
function objectEntries(obj) { const entries = []; for (const key in obj) { if (Object.hasOwn(obj, key)) { entries.push([key, obj[key]]); } } return entries; }
しかし、このコードは十分ではありません。オブジェクトが巨大だった場合はどうなるでしょうか?配列ベースのアプローチのパフォーマンスは、この関数を実行するプロセス全体にわたってメモリに保存する必要があります。で、また使うとしたら?同じように新しい配列をメモリ内に構築して保持する必要があります。現実の世界では、これは深刻なパフォーマンスの問題につながる可能性があり、ある時点でパフォーマンスを考慮する必要があります。ただし、Symbol.iterator が助けとなる、これらの問題すべてを解決するエレガントなソリューションがあります!
更新されたスニペットは次のとおりです:
function objectEntries(obj) { return { [Symbol.iterator]() { const keys = Object.keys(obj); let index = 0; return { next() { if (index < keys.length) { const key = keys[index++]; return { value: [key, obj[key]], done: false }; } return { done: true }; } }; } }; }
繰り返しに Symbol.iterator を使用する理由
最初の実装では、objectEntries 関数はメモリ内にすべてのエントリ ([キー、値] ペア) の配列を構築します。これは、オブジェクトに多数のプロパティがある場合に問題になる可能性があります。すべてのエントリを配列に格納するということは、事前にすべての単一ペアにメモリを割り当てる必要があることを意味します。このアプローチは、オブジェクトが小さい場合にはかなり問題ありませんが、オブジェクトのサイズが大きくなるとすぐに非効率になり、単純に遅くなります。
更新されたコードでは、反復ロジックを保持するオブジェクトに [Symbol.iterator] を定義します。段階的に見てみましょう:
カスタム ループへの Symbol.iterator の適用
これらのメソッドを使用してループの動作をより詳細に制御する方法を詳しく見てみましょう。提供されている各例は、配列データを操作する独自の方法を示しており、コードに大幅な柔軟性を与えます。各方法の意味と、それらをさまざまなシナリオでどのように活用できるかを検討します。
これらの例では、コードを読みやすくするためにサンプル メソッドを使用して Array プロトタイプ (プロトタイプの詳細はこちら) を拡張します。早速始めましょう!
たとえば、この reverseIterator メソッドは、最新のメッセージを最初に表示したいチャット アプリケーションなどで役立ちます。チャット アプリケーションは、大量のデータ (この場合はメッセージ) を保持することで有名です。 reverseIterator を使用すると、新しい反転配列を作成することなく、メッセージのリストを反復処理し、希望の順序で表示できます。
function objectEntries(obj) { const entries = []; for (const key in obj) { if (Object.hasOwn(obj, key)) { entries.push([key, obj[key]]); } } return entries; }
このユニークなメソッドを使用すると、一意の値のみが生成されるようにしながら、配列を反復処理できます。これは、事前にフィルタリングしたり、より多くのメモリを使用したりすることなく、その場で重複を排除するのに非常に役立ちます。
function objectEntries(obj) { return { [Symbol.iterator]() { const keys = Object.keys(obj); let index = 0; return { next() { if (index < keys.length) { const key = keys[index++]; return { value: [key, obj[key]], done: false }; } return { done: true }; } }; } }; }
以下のチャンク メソッドは、大規模なデータセットを扱う場合に便利です。データセットを小さなチャンクで処理してメモリ使用量を削減し、パフォーマンスを向上させることができます。 CSV ファイルなどからデータをインポートしているとします。よりスケーラブルなセグメントでデータを読み取って処理できます。さらに、Web ユーザー インターフェイスでは、チャンクをページネーションに使用できるため、ページごとに特定の数のアイテムを表示したり、無限ローダーをより適切に管理したりすることができます。
Array.prototype.reverseIterator = function() { let index = this.length - 1; return { [Symbol.iterator]: () => ({ next: () => { if (index >= 0) { return { value: this[index--], done: false }; } return { done: true }; } }) }; }; const numbers = [1, 2, 3, 4, 5]; for (const num of numbers.reverseIterator()) { console.log(num); // 5, 4, 3, 2, 1 }
結論
この記事では、Symbol.iterator がロジックをカスタマイズし、ループの効率を向上させる方法を検討しました。 Array.prototype (またはその効果を持つ他の反復可能なメソッド) にカスタムの反復可能メソッドを実装することで、メモリ使用量を効果的に管理し、ループの実行方法を制御できます。
objectEntries の最初の例では、大きなオブジェクトを処理するときに配列ベースのアプローチがどのようにパフォーマンスの問題を引き起こす可能性があるかを示しました。ただし、SYmbol.iterator を使用することで、不必要なメモリ割り当てのオーバーヘッドなしでオブジェクト エントリを反復処理できる効率的なソリューションを作成しました。
また、Array.prototype を拡張することで、開発者が日常的に対処しなければならない現実のさまざまなシナリオをどのように促進できるかについて、いくつかの実践例も検討しました。
これらの強力なツールを自由に使用できるため、アプリのパフォーマンスへの影響がほぼゼロで、JavaScript での複雑なデータ処理シナリオをより適切に解決できるようになります。
以上がSymbol.iterator でループを制御するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。