面向急切程序员的 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 其他

  测验

参见 测验应用程序