while
迭代可迭代物件同步迭代是一種協定(介面加上使用它們的規則),用於連接 JavaScript 中兩組實體
資料來源:一方面,資料的形狀和大小各不相同。在 JavaScript 的標準函式庫中,您有線性資料結構陣列、有序集合 Set(元素按新增時間排序)、有序字典 Map(條目按新增時間排序)等等。在函式庫中,您可能會找到樹狀資料結構等等。
資料使用者:另一方面,您有一整類建構和演算法,它們只需要依序存取其輸入:一次一個值,直到拜訪所有值。範例包括 for-of
迴圈和散佈到函式呼叫(透過 ...
)。
迭代協定透過介面 Iterable
連接這兩組:資料來源透過「它」依序傳送其內容;資料使用者透過「它」取得其輸入。
圖 18 說明迭代如何運作:資料使用者使用介面 Iterable
;資料來源實作它。
JavaScript 實作介面的方式
在 JavaScript 中,如果物件擁有介面中描述的所有方法,則表示該物件實作該介面。本章中提到的介面僅存在於 ECMAScript 規格中。
資料的來源和使用者都能從這種安排中獲益
如果您開發新的資料結構,您只需實作 Iterable
,就能立即套用大量工具。
如果您撰寫使用反覆運算的程式碼,它會自動與許多資料來源搭配運作。
兩個角色(由介面描述)構成了反覆運算的核心(圖 19)
以下是反覆運算通訊協定的介面的類型定義(以 TypeScript 的表示法表示)
interface Iterable<T> {
Symbol.iterator]() : Iterator<T>;
[
}
interface Iterator<T> {
next() : IteratorResult<T>;
}
interface IteratorResult<T> {
: T;
value: boolean;
done }
介面使用方式如下
Symbol.iterator
的方法,向 Iterable
要求一個反覆運算器。Iterator
會透過其方法 .next()
傳回反覆運算的值。.value
是反覆運算的值。.done
指出是否已到達反覆運算的結尾。它會在最後一個反覆運算的值之後為 true
,在此之前為 false
。以下是使用反覆運算通訊協定的範例
const iterable = ['a', 'b'];
// The iterable is a factory for iterators:
const iterator = iterable[Symbol.iterator]();
// Call .next() until .done is true:
.deepEqual(
assert.next(), { value: 'a', done: false });
iterator.deepEqual(
assert.next(), { value: 'b', done: false });
iterator.deepEqual(
assert.next(), { value: undefined, done: true }); iterator
while
反覆運算可迭代物件以下程式碼示範如何使用 while
迴圈反覆運算可迭代物件
function logAll(iterable) {
const iterator = iterable[Symbol.iterator]();
while (true) {
const {value, done} = iterator.next();
if (done) break;
console.log(value);
}
}
logAll(['a', 'b']);
// Output:
// 'a'
// 'b'
練習:手動使用同步反覆運算
exercises/sync-iteration-use/sync_iteration_manually_exrc.mjs
我們已經看過如何手動使用反覆運算通訊協定,而且這相對繁瑣。但是,通訊協定的用意並非直接使用,而是透過建構在其上的更高階語言結構來使用。本節將說明其樣貌。
JavaScript 的陣列是可迭代的。這讓我們可以使用 for-of
迴圈
const myArray = ['a', 'b', 'c'];
for (const x of myArray) {
console.log(x);
}// Output:
// 'a'
// 'b'
// 'c'
透過陣列模式解構(稍後說明)在幕後也會使用反覆運算
const [first, second] = myArray;
.equal(first, 'a');
assert.equal(second, 'b'); assert
JavaScript 的 Set 資料結構是可迭代的。這表示 for-of
可行
const mySet = new Set().add('a').add('b').add('c');
for (const x of mySet) {
console.log(x);
}// Output:
// 'a'
// 'b'
// 'c'
陣列解構也是
const [first, second] = mySet;
.equal(first, 'a');
assert.equal(second, 'b'); assert
下列內建資料來源是可迭代的
若要迭代物件的屬性,您需要像 Object.keys()
和 Object.entries()
等輔助程式。這是必要的,因為屬性存在於與資料結構層級無關的不同層級。
本節列出使用同步迭代的建構。
透過陣列樣式解構
const [x,y] = iterable;
散佈(透過 ...
)到函式呼叫和陣列文字
func(...iterable);
const arr = [...iterable];
for-of
迴圈
for (const x of iterable) { /*···*/ }
yield*
:
function* generatorFunction() {
yield* iterable;
}
const obj = Object.fromEntries(iterableOverKeyValuePairs);
const arr = Array.from(iterable);
const m = new Map(iterableOverKeyValuePairs);
const wm = new WeakMap(iterableOverKeyValuePairs);
const s = new Set(iterableOverElements);
const ws = new WeakSet(iterableOverElements);
Promise 組合函式:Promise.all()
等
const promise1 = Promise.all(iterableOverPromises);
const promise2 = Promise.race(iterableOverPromises);
const promise3 = Promise.any(iterableOverPromises);
const promise4 = Promise.allSettled(iterableOverPromises);
測驗
請參閱 測驗應用程式。