針對急躁程式設計師的 JavaScript(ES2022 版本)
請支持這本書:購買捐款
(廣告,請不要封鎖。)

30 同步迭代



30.1 同步迭代是什麼?

同步迭代是一種協定(介面加上使用它們的規則),用於連接 JavaScript 中兩組實體

迭代協定透過介面 Iterable 連接這兩組:資料來源透過「它」依序傳送其內容;資料使用者透過「它」取得其輸入。

Figure 18: Data consumers such as the for-of loop use the interface Iterable. Data sources such as Arrays implement that interface.

圖 18 說明迭代如何運作:資料使用者使用介面 Iterable;資料來源實作它。

  JavaScript 實作介面的方式

在 JavaScript 中,如果物件擁有介面中描述的所有方法,則表示該物件實作該介面。本章中提到的介面僅存在於 ECMAScript 規格中。

資料的來源和使用者都能從這種安排中獲益

30.2 核心反覆運算結構:可迭代物件和反覆運算器

兩個角色(由介面描述)構成了反覆運算的核心(圖 19

Figure 19: Iteration has two main interfaces: Iterable and Iterator. The former has a method that returns the latter.

以下是反覆運算通訊協定的介面的類型定義(以 TypeScript 的表示法表示)

interface Iterable<T> {
  [Symbol.iterator]() : Iterator<T>;
}

interface Iterator<T> {
  next() : IteratorResult<T>;
}

interface IteratorResult<T> {
  value: T;
  done: boolean;
}

介面使用方式如下

30.3 手動反覆運算

以下是使用反覆運算通訊協定的範例

const iterable = ['a', 'b'];

// The iterable is a factory for iterators:
const iterator = iterable[Symbol.iterator]();

// Call .next() until .done is true:
assert.deepEqual(
  iterator.next(), { value: 'a', done: false });
assert.deepEqual(
  iterator.next(), { value: 'b', done: false });
assert.deepEqual(
  iterator.next(), { value: undefined, done: true });

30.3.1 透過 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

30.4 反覆運算的實務應用

我們已經看過如何手動使用反覆運算通訊協定,而且這相對繁瑣。但是,通訊協定的用意並非直接使用,而是透過建構在其上的更高階語言結構來使用。本節將說明其樣貌。

30.4.1 反覆運算陣列

JavaScript 的陣列是可迭代的。這讓我們可以使用 for-of 迴圈

const myArray = ['a', 'b', 'c'];

for (const x of myArray) {
  console.log(x);
}
// Output:
// 'a'
// 'b'
// 'c'

透過陣列模式解構(稍後說明)在幕後也會使用反覆運算

const [first, second] = myArray;
assert.equal(first, 'a');
assert.equal(second, 'b');

30.4.2 反覆運算集合

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;
assert.equal(first, 'a');
assert.equal(second, 'b');

30.5 快速參考:同步迭代

30.5.1 可迭代資料來源

下列內建資料來源是可迭代的

若要迭代物件的屬性,您需要像 Object.keys()Object.entries() 等輔助程式。這是必要的,因為屬性存在於與資料結構層級無關的不同層級。

30.5.2 同步迭代語言建構

本節列出使用同步迭代的建構。

30.5.2.1 迭代的語言建構
30.5.2.2 將可迭代轉換為資料結構
30.5.2.3 其他

  測驗

請參閱 測驗應用程式