Iterator
Baseline 廣泛可用 *
一個 Iterator 物件是一個符合迭代器協議的物件,它透過提供一個 next() 方法來返回一個迭代器結果物件。所有內建迭代器都繼承自 Iterator 類。Iterator 類提供了一個 [Symbol.iterator]() 方法,該方法返回迭代器物件本身,使得迭代器也成為可迭代物件。它還提供了一些用於處理迭代器的輔助方法。
描述
以下是所有內建的 JavaScript 迭代器:
- 由
Array.prototype.values()、Array.prototype.keys()、Array.prototype.entries()、Array.prototype[Symbol.iterator]()、TypedArray.prototype.values()、TypedArray.prototype.keys()、TypedArray.prototype.entries()、TypedArray.prototype[Symbol.iterator]()和arguments[Symbol.iterator]()返回的 陣列迭代器。 - 由
String.prototype[Symbol.iterator]()返回的 字串迭代器。 - 由
Map.prototype.values()、Map.prototype.keys()、Map.prototype.entries()和Map.prototype[Symbol.iterator]()返回的 Map 迭代器。 - 由
Set.prototype.values()、Set.prototype.keys()、Set.prototype.entries()和Set.prototype[Symbol.iterator]()返回的 Set 迭代器。 - 由
RegExp.prototype[Symbol.matchAll]()和String.prototype.matchAll()返回的 RegExp 字串迭代器。 - 由生成器函式返回的
Generator物件。 - 由
Intl.Segmenter.prototype.segment()返回的Segments物件的[Symbol.iterator]()方法返回的 分段迭代器。 - 由迭代器輔助方法(如
Iterator.prototype.filter()和Iterator.prototype.map())返回的 迭代器輔助器。
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 類本身提供了一些用於處理迭代器的輔助方法。例如,您可能會嘗試以下操作:
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() 方法:
const totalDeposit = nameToDeposit.values().reduce((a, b) => a + b);
這種方法可能更有效,尤其是在記憶體方面,因為它只迭代迭代器一次,而不記憶任何中間值。迭代器輔助方法對於處理無限迭代器是必要的。
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.drop() 和 Iterator.prototype.take() 結合起來有點類似於 Array.prototype.slice()。
迭代器輔助物件
注意: 迭代器輔助物件和迭代器輔助方法是兩個不同的概念。迭代器輔助物件可以在執行時檢測到,而“迭代器輔助方法”只是用於理解的一組方法的名稱。迭代器輔助器可能指物件或方法,具體取決於上下文。
在迭代器輔助方法中,filter()、flatMap()、map()、drop() 和 take() 返回一個新的 迭代器輔助器 物件。迭代器輔助器也是一個 Iterator 例項,這使得這些輔助方法可以鏈式呼叫。所有迭代器輔助物件都繼承自一個公共原型物件,該物件實現了迭代器協議:
迭代器輔助器與底層迭代器共享相同的資料來源,因此迭代迭代器輔助器也會導致底層迭代器被迭代。沒有辦法“分叉”一個迭代器以使其能夠多次迭代。
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() 方法。
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]()-
如果存在,則呼叫
this的return()方法。這實現了可處置協議,並允許在使用using或await using時對其進行處置。 Iterator.prototype[Symbol.iterator]()-
返回迭代器物件本身。這使得迭代器物件也可以是可迭代的。
示例
將迭代器用作可迭代物件
所有內建迭代器也都是可迭代的,因此您可以在 for...of 迴圈中使用它們:
const arrIterator = [1, 2, 3].values();
for (const value of arrIterator) {
console.log(value);
}
// Logs: 1, 2, 3
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-%iteratorprototype%-object |
瀏覽器相容性
載入中…