「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > Symbol.iterator でループを制御する

Symbol.iterator でループを制御する

2024 年 11 月 18 日に公開
ブラウズ:316

Take control of loops with Symbol.iterator

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 



繰り返しに Symbol.iterator を使用する理由

最初の実装では、objectEntries 関数はメモリ内にすべてのエントリ ([キー、値] ペア) の配列を構築しますが、オブジェクトに多数のプロパティがある場合に問題が発生する可能性があります。すべてのエントリを配列に格納するということは、事前にすべての単一ペアにメモリを割り当てる必要があることを意味します。このアプローチは、オブジェクトが小さい場合にはかなり問題ありませんが、オブジェクトのサイズが大きくなるとすぐに非効率になり、単純に遅くなります。

更新されたコードでは、反復ロジックを保持するオブジェクトに [Symbol.iterator] を定義します。段階的に見てみましょう:

  • Initialize Keys: Object.keys(obj) はオブジェクト obj からキーの配列を取得します。このキーのリストにより、すべてのエントリを保存しなくても、どのプロパティにアクセスする必要があるかを正確に知ることができます。
  • インデックス ポインターを使用する: 変数インデックスは、キー配列内の現在位置を追跡します。これがループ内に存在する唯一の状態です。
  • 次のメソッドを定義します: next() 関数は、インデックスを使用して現在のキーを取得し、それをインクリメントします。これは、各 [key, obj[key]] ペアを値として返し、すべてのキーを反復処理したときに、done: true を設定します。
  • これを行うことで、前もってエントリの配列全体を作成するメモリ コストを発生させずに、objectEntries があらゆる for...of ループと互換性を持つようになります。

カスタム ループへの Symbol.iterator の適用

これらのメソッドを使用してループの動作をより詳細に制御する方法を詳しく見てみましょう。提供されている各例は、配列データを操作する独自の方法を示しており、コードに大幅な柔軟性を与えます。各方法の影響と、それらをさまざまなシナリオでどのように活用できるかを検討します。

これらの例では、コードを読みやすくするためにサンプル メソッドを使用して Array プロトタイプ (プロトタイプの詳細はこちら) を拡張します。早速始めましょう!

たとえば、この reverseIterator メソッドは、最新のメッセージを最初に表示したいチャット アプリケーションなどで役立ちます。チャット アプリケーションは、大量のデータ (この場合はメッセージ) を保持することで有名です。 reverseIterator を使用すると、新しい逆配列を作成しなくても、メッセージのリストを反復処理して希望の順序で表示できます。

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
}

このユニークなメソッドを使用すると、一意の値のみが生成されるようにしながら、配列を反復処理できます。これは、事前にフィルタリングしたり、より多くのメモリを使用したりすることなく、その場で重複を排除するのに非常に役立ちます。

Array.prototype.unique = function() {
  const seen = new Set();
  return {
    [Symbol.iterator]: () => ({
      next: () => {
        for (let i = 0; i 



以下のチャンク メソッドは、大規模なデータセットを扱う場合に便利です。データセットを小さなチャンクで処理して、メモリ使用量を削減し、パフォーマンスを向上させることができます。 CSV ファイルなどからデータをインポートしているとします。よりスケーラブルなセグメントでデータを読み取って処理できます。さらに、Web ユーザー インターフェイスでは、チャンクをページネーションに使用できるため、ページごとに特定の数の項目を表示したり、無限ローダーをより適切に管理したりできます。

Array.prototype.chunk = function(size) {
  let index = 0;
  return {
    [Symbol.iterator]: () => ({
      next: () => {
        if (index 



結論

この記事では、Symbol.iterator がロジックをカスタマイズし、ループの効率を向上させる方法を検討しました。 Array.prototype (またはその効果を持つ他の反復可能なメソッド) にカスタムの反復可能メソッドを実装することで、メモリ使用量を効果的に管理し、ループの実行方法を制御できます。

objectEntries の最初の例では、大きなオブジェクトを処理するときに配列ベースのアプローチがどのようにパフォーマンスの問題を引き起こす可能性があるかを示しました。ただし、SYmbol.iterator を使用することで、不必要なメモリ割り当てのオーバーヘッドなしでオブジェクト エントリを反復処理できる効率的なソリューションを作成しました。

また、Array.prototype を拡張することで、開発者が日常的に対処しなければならないさまざまな現実世界のシナリオをどのように促進できるかについて、いくつかの実践例も検討しました。

これらの強力なツールを自由に使用できるため、アプリのパフォーマンスへの影響がほぼゼロに近い JavaScript での複雑なデータ処理シナリオをより適切に解決できるようになります。

リリースステートメント この記事は次の場所に転載されています: https://dev.to/vanyaxk/take-control-of-loops-with-symboliterator-4lon?1 侵害がある場合は、[email protected] に連絡して削除してください。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3