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

Linda Hamilton
リリース: 2024-11-08 07:16:02
オリジナル
747 人が閲覧しました

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 < keys.length) {
            const key = keys[index++];
            return { value: [key, obj[key]], done: false };
          }
          return { done: true };
        }
      };
    }
  };
}
ログイン後にコピー
ログイン後にコピー

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

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

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

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

カスタム ループへの 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 サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!