Iterator

Baseline 廣泛可用 *

此特性已非常成熟,可在多種裝置和瀏覽器版本上使用。自 ⁨2016 年 9 月⁩以來,它已在各大瀏覽器中可用。

* 此特性的某些部分可能存在不同級別的支援。

一個 Iterator 物件是一個符合迭代器協議的物件,它透過提供一個 next() 方法來返回一個迭代器結果物件。所有內建迭代器都繼承自 Iterator 類。Iterator 類提供了一個 [Symbol.iterator]() 方法,該方法返回迭代器物件本身,使得迭代器也成為可迭代物件。它還提供了一些用於處理迭代器的輔助方法。

描述

以下是所有內建的 JavaScript 迭代器:

Web API 也可能返回迭代器。有些重用了核心 JavaScript 迭代器,而另一些則定義了自己的迭代器。例如:

  • 類陣列物件,例如 NodeList,從其各自的 keys()values()entries()[Symbol.iterator]() 方法返回一個 陣列迭代器
  • 來自 Web API 的類 Map 物件,例如 Headers,從其各自的 keys()values()entries()[Symbol.iterator]() 方法返回其自己的迭代器型別,如 Headers 迭代器
  • 來自 Web API 的類 Set 物件,例如 FontFaceSet,從其各自的 keys()values()entries()[Symbol.iterator]() 方法返回其自己的迭代器型別,如 FontFaceSet 迭代器

注意: NodeIterator 和其他舊介面雖然名稱如此,但並不符合迭代器協議可迭代協議

這些迭代器中的每一個都有一個獨特的原型物件,它定義了特定迭代器使用的 next() 方法。例如,所有字串迭代器物件都繼承自一個隱藏物件 StringIteratorPrototype,它有一個 next() 方法,該方法按程式碼點迭代字串。StringIteratorPrototype 還有一個 [Symbol.toStringTag] 屬性,其初始值為字串 "String Iterator"。此屬性在 Object.prototype.toString() 中使用。類似地,其他迭代器原型也有自己的 [Symbol.toStringTag] 值,這些值與上面給出的名稱相同。

所有這些原型物件都繼承自 Iterator.prototype,它提供了一個 [Symbol.iterator]() 方法,該方法返回迭代器物件本身,使迭代器也成為可迭代物件

迭代器輔助方法

注意: 這些方法是迭代器輔助方法,而不是可迭代物件輔助方法,因為物件可迭代的唯一要求是存在 [Symbol.iterator]() 方法。沒有共享的原型來安裝這些方法。

Iterator 類本身提供了一些用於處理迭代器的輔助方法。例如,您可能會嘗試以下操作:

js
const nameToDeposit = new Map([
  ["Anne", 1000],
  ["Bert", 1500],
  ["Carl", 2000],
]);

const totalDeposit = [...nameToDeposit.values()].reduce((a, b) => a + b);

這首先將 Map.prototype.values() 返回的迭代器轉換為陣列,然後使用 Array.prototype.reduce() 方法計算總和。但是,這既建立了一箇中間陣列,又對陣列進行了兩次迭代。相反,您可以直接使用迭代器本身的 reduce() 方法:

js
const totalDeposit = nameToDeposit.values().reduce((a, b) => a + b);

這種方法可能更有效,尤其是在記憶體方面,因為它只迭代迭代器一次,而不記憶任何中間值。迭代器輔助方法對於處理無限迭代器是必要的。

js
function* fibonacci() {
  let current = 1;
  let next = 1;
  while (true) {
    yield current;
    [current, next] = [next, current + next];
  }
}

const seq = fibonacci();
const firstThreeDigitTerm = seq.find((n) => n >= 100);

您無法將 seq 轉換為陣列,因為它是無限的。相反,您可以使用迭代器本身的 find() 方法,該方法只在必要時迭代 seq 以找到滿足條件的第一個值。

您會發現許多迭代器方法與陣列方法類似,例如:

迭代器方法 陣列方法
Iterator.prototype.every() Array.prototype.every()
Iterator.prototype.filter() Array.prototype.filter()
Iterator.prototype.find() Array.prototype.find()
Iterator.prototype.flatMap() Array.prototype.flatMap()
Iterator.prototype.forEach() Array.prototype.forEach()
Iterator.prototype.map() Array.prototype.map()
Iterator.prototype.reduce() Array.prototype.reduce()
Iterator.prototype.some() Array.prototype.some()

Iterator.prototype.drop()Iterator.prototype.take() 結合起來有點類似於 Array.prototype.slice()

迭代器輔助物件

注意: 迭代器輔助物件迭代器輔助方法是兩個不同的概念。迭代器輔助物件可以在執行時檢測到,而“迭代器輔助方法”只是用於理解的一組方法的名稱。迭代器輔助器可能指物件或方法,具體取決於上下文。

在迭代器輔助方法中,filter()flatMap()map()drop()take() 返回一個新的 迭代器輔助器 物件。迭代器輔助器也是一個 Iterator 例項,這使得這些輔助方法可以鏈式呼叫。所有迭代器輔助物件都繼承自一個公共原型物件,該物件實現了迭代器協議:

next()

呼叫底層迭代器的 next() 方法,將輔助方法應用於結果,並返回結果。

return()

呼叫底層迭代器的 return() 方法,並返回結果。

迭代器輔助器與底層迭代器共享相同的資料來源,因此迭代迭代器輔助器也會導致底層迭代器被迭代。沒有辦法“分叉”一個迭代器以使其能夠多次迭代。

js
const it = [1, 2, 3].values();
const it2 = it.drop(0); // Essentially a copy
console.log(it.next().value); // 1
console.log(it2.next().value); // 2
console.log(it.next().value); // 3

真正的迭代器

有兩種“迭代器”:符合迭代器協議的物件(最少只要求存在 next() 方法),以及繼承自 Iterator 類並享有輔助方法的物件。它們並不相互包含——繼承自 Iterator 的物件不會自動成為迭代器,因為 Iterator 類不定義 next() 方法。相反,物件需要自己定義一個 next() 方法。一個真正的迭代器是既符合迭代器協議又繼承自 Iterator 的迭代器,並且大多數程式碼期望迭代器是真正的迭代器,並且可迭代物件返回真正的迭代器。要建立真正的迭代器,可以定義一個擴充套件 Iterator 的類,或使用 Iterator.from() 方法。

js
class MyIterator extends Iterator {
  next() {
    // …
  }
}

const myIterator = Iterator.from({
  next() {
    // …
  },
});

建構函式

Iterator()

旨在被建立迭代器的其他類擴充套件。如果單獨構造,會丟擲錯誤。

靜態方法

Iterator.from()

從迭代器或可迭代物件建立一個新的 Iterator 物件。

例項屬性

這些屬性在 Iterator.prototype 上定義,並由所有 Iterator 例項共享。

Iterator.prototype.constructor

建立例項物件的建構函式。對於 Iterator 例項,初始值是 Iterator 建構函式。

Iterator.prototype[Symbol.toStringTag]

[Symbol.toStringTag] 屬性的初始值為字串 "Iterator"。此屬性在 Object.prototype.toString() 中使用。

注意: 與大多數內建類上的 [Symbol.toStringTag] 不同,Iterator.prototype[Symbol.toStringTag] 是可寫的,這是出於 Web 相容性原因。

例項方法

Iterator.prototype.drop()

返回一個新的迭代器輔助物件,該物件跳過此迭代器開頭的給定數量的元素。

Iterator.prototype.every()

測試迭代器產生的所有元素是否透過提供的函式實現的測試。

Iterator.prototype.filter()

返回一個新的迭代器輔助物件,該物件只生成迭代器中那些提供的回撥函式返回 true 的元素。

Iterator.prototype.find()

返回迭代器產生的第一個滿足提供的測試函式的元素。如果沒有值滿足測試函式,則返回 undefined

Iterator.prototype.flatMap()

返回一個新的迭代器輔助物件,該物件接受原始迭代器中的每個元素,透過對映函式處理它,並生成對映函式返回的元素(這些元素包含在另一個迭代器或可迭代物件中)。

Iterator.prototype.forEach()

對迭代器產生的每個元素執行一次提供的函式。

Iterator.prototype.map()

返回一個新的迭代器輔助物件,該物件生成迭代器的元素,每個元素都由對映函式轉換。

Iterator.prototype.reduce()

對迭代器產生的每個元素執行一個使用者提供的“reducer”回撥函式,傳入對前一個元素計算的返回值。執行 reducer 對所有元素的最終結果是一個單一值。

Iterator.prototype.some()

測試迭代器中至少有一個元素透過提供的函式實現的測試。它返回一個布林值。

Iterator.prototype.take()

返回一個新的迭代器輔助物件,該物件生成此迭代器中給定數量的元素,然後終止。

Iterator.prototype.toArray()

建立一個新的 Array 例項,其中填充了從迭代器生成的元素。

Iterator.prototype[Symbol.dispose]()

如果存在,則呼叫 thisreturn() 方法。這實現了可處置協議,並允許在使用 usingawait using 時對其進行處置。

Iterator.prototype[Symbol.iterator]()

返回迭代器物件本身。這使得迭代器物件也可以是可迭代的。

示例

將迭代器用作可迭代物件

所有內建迭代器也都是可迭代的,因此您可以在 for...of 迴圈中使用它們:

js
const arrIterator = [1, 2, 3].values();
for (const value of arrIterator) {
  console.log(value);
}
// Logs: 1, 2, 3

規範

規範
ECMAScript® 2026 語言規範
# sec-%iteratorprototype%-object

瀏覽器相容性

另見