首頁 > web前端 > js教程 > 主體

使用 Symbol.iterator 控制循環

Linda Hamilton
發布: 2024-11-08 07:16:02
原創
806 人瀏覽過

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 函數會在記憶體中建立所有條目([key, value] 對)的數組,如果物件具有大量屬性,這可能會出現問題。將所有條目儲存在數組中意味著我們必須提前為每一對分配記憶體。這種方法對於較小的物件來說相當不錯,但隨著物件大小的增加,它很快就會變得低效並且速度變慢。

在更新後的程式碼中,我們在保存迭代邏輯的物件上定義了 [Symbol.iterator]。讓我們一步步分解:

  • 初始化鍵:Object.keys(obj) 從物件 obj 取得鍵數組。這個鍵列表使我們能夠準確地知道我們需要存取哪些屬性,而無需儲存每個條目。
  • 使用索引指標:變數索引來追蹤我們在鍵數組中的目前位置。這是我們在循環中唯一的狀態。
  • 定義 next 方法:next() 函數使用索引來檢索目前鍵並遞增它。它會傳回每個 [key, obj[key]] 對作為值,並在迭代完所有鍵後設定 did: true。
  • 透過這樣做,我們使 objectEntries 能夠與任何 for...of 迴圈相容,而無需預先建立整個條目數組的記憶體成本。

將 Symbol.iterator 套用至自訂循環

讓我們更深入地了解這些方法如何提供更多對循環行為的控制。提供的每個範例都示範了與陣列資料互動的獨特方式,為您的程式碼增加了許多靈活性。我們將探討每種方法的含義以及如何在不同場景中利用它們。

在這些範例中,我將使用範例方法擴展數組原型(有關原型的更多資訊),以使我的程式碼更易於閱讀。讓我們直接開始吧!

例如,這個反向迭代器方法在聊天應用程式之類的應用程式中很有用,您可能想要先顯示最新的消息。聊天應用程式因擁有大量資料(在本例中為訊息)而臭名昭著。使用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中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板