## 27 同步迭代
> 原文: [http://exploringjs.com/impatient-js/ch_sync-iteration.html](http://exploringjs.com/impatient-js/ch_sync-iteration.html)
### 27.1 什么是同步迭代?
同步迭代是一個 *協議*(接口加上使用它們的規則),它連接 JavaScript 中的兩組實體:
- **數據來源:** 一方面,數據有各種形式和大小。在 JavaScript 的標準庫中,有線性數據結構 Array,有序集合 Set(元素按添加時間排序),有序字典 Map(條目按添加時間排序)等等。在庫中,您還可以找到樹形數據結構等。
- **數據消費者:** 另一方面,你有一整套機制和算法,只需要按順序訪問:一次一個,再加上告訴我什么時候完成的方法。示例包括`for-of`循環并擴展到數組字面值(通過`...`)。
迭代協議通過接口`Iterable`連接這兩部分:數據源按順序“穿過它”傳遞它們的內容;數據消費者通過它獲得輸入。

Figure 18: Data consumers such as the `for-of` loop use the interface `Iterable`. Data sources such as `Arrays` implement that interface.
圖中的圖表 [18](#fig:iterable-implementers-clients) 說明了迭代的工作原理:數據消費者使用接口`Iterable`;數據源實現它。
> **JavaScript 實現接口的方式**
>
> 在 JavaScript 中,如果一個對象具有接口聲明的所有方法,即為 *實現* 該接口。本章中提到的接口僅存在于ECMAScript規范中。
數據的來源和消費者都從這種安排中獲益:
* 如果您開發新的數據結構,則只需要實現`Iterable`,就可以立即應用大量工具。
* 如果編寫使用迭代的代碼,它會自動使用許多數據源。
### 27.2 核心迭代構造:迭代接口和迭代器
兩個角色(由接口描述)構成了迭代的核心(圖 [19](#fig:iteration-protocol) ):
* *iterable* 接口是一個對象,其內容可以順序遍歷。
* *迭代器* 是用于遍歷的指針。

Figure 19: 迭代有兩個主要的接口: `Iterable` 和 `Iterator`。前者有一種返回后者的方法。
這些是迭代協議接口的類型定義(以 TypeScript 的表示法):
```js
interface Iterable<T> {
[Symbol.iterator]() : Iterator<T>;
}
interface Iterator<T> {
next() : IteratorResult<T>;
}
interface IteratorResult<T> {
value: T;
done: boolean;
}
```
接口使用如下:
* 您可以通過鍵為 `Symbol.iterator` 的方法向 `Iterable` 接口請求迭代器。
* `Iterator` 通過其方法 `.next()` 返回迭代值。
* 這些值不會直接返回,而是包含在具有兩個屬性的對象中:
* `.value` 是迭代值。
* `.done` 表示是否已達到迭代結束。在最后一次迭代值和 `false` 之后是`true`。
### 27.3 手動迭代
這是使用迭代協議的示例:
```js
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 });
```
#### 27.3.1 通過`while`迭代一個迭代(Iterable)
以下代碼演示了如何使用`while`循環迭代一個迭代:
```js
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`
### 27.4 實踐中的迭代
我們已經看到了如何手動使用迭代協議,這是相對麻煩的。但該協議并不是直接使用的——它旨在通過構建在其上的更高級語言結構來使用。本節介紹了它看起來是什么樣的。
#### 27.4.1 迭代數組(Array)
JavaScript 的數組是可迭代的。這使我們可以使用`for-of`循環:
```js
const myArray = ['a', 'b', 'c'];
for (const x of myArray) {
console.log(x);
}
// Output:
// 'a'
// 'b'
// 'c'
```
通過數組模式進行解構(稍后解釋)也使用了迭代:
```js
const [first, second] = myArray;
assert.equal(first, 'a');
assert.equal(second, 'b');
```
#### 27.4.2 迭代 Set
JavaScript 的 Set 數據結構是可迭代的。這意味著,`for-of`有效:
```js
const mySet = new Set().add('a').add('b').add('c');
for (const x of mySet) {
console.log(x);
}
// Output:
// 'a'
// 'b'
// 'c'
```
和數組解構一樣:
```js
const [first, second] = mySet;
assert.equal(first, 'a');
assert.equal(second, 'b');
```
### 27.5 快速參考:同步迭代
#### 27.5.1 可迭代數據源
以下內置數據源是可迭代的:
* `Arrays`
* `Strings`
* `Maps`
* `Sets`
* (瀏覽器:DOM 數據結構)
要迭代對象的屬性,你需要一些“幫手”,諸如 `Object.keys()` 和 `Object.entries()` 。這很必要,因為屬性存在于與數據結構級別互補的不同級別。
#### 27.5.2 迭代結構
以下構造都基于迭代:
* 通過數組模式進行解構:
```js
const [x,y] = iterable;
```
* `for-of`循環:
```js
for (const x of iterable) { /*···*/ }
```
* `Array.from()`:
```js
const arr = Array.from(iterable);
```
* 將(通過`...`)傳播到數組和函數調用中:
```js
const arr = [...iterable];
func(...iterable);
```
* `new Map()`和`new Set()`:
```js
const m = new Map(iterableOverKeyValuePairs);
const s = new Set(iterableOverElements);
```
* `Promise.all()`和`Promise.race()`:
```js
const promise1 = Promise.all(iterableOverPromises);
const promise2 = Promise.race(iterableOverPromises);
```
* `yield*`:
```js
function* generatorFunction() {
yield* iterable;
}
```
>  **測驗**
>
> 參見[測驗應用程序](/docs/11.md#91測驗)。
- I.背景
- 1.關于本書(ES2019 版)
- 2.常見問題:本書
- 3. JavaScript 的歷史和演變
- 4.常見問題:JavaScript
- II.第一步
- 5.概覽
- 6.語法
- 7.在控制臺上打印信息(console.*)
- 8.斷言 API
- 9.測驗和練習入門
- III.變量和值
- 10.變量和賦值
- 11.值
- 12.運算符
- IV.原始值
- 13.非值undefined和null
- 14.布爾值
- 15.數字
- 16. Math
- 17. Unicode - 簡要介紹(高級)
- 18.字符串
- 19.使用模板字面值和標記模板
- 20.符號
- V.控制流和數據流
- 21.控制流語句
- 22.異常處理
- 23.可調用值
- VI.模塊化
- 24.模塊
- 25.單個對象
- 26.原型鏈和類
- 七.集合
- 27.同步迭代
- 28.數組(Array)
- 29.類型化數組:處理二進制數據(高級)
- 30.映射(Map)
- 31. WeakMaps(WeakMap)
- 32.集(Set)
- 33. WeakSets(WeakSet)
- 34.解構
- 35.同步生成器(高級)
- 八.異步
- 36. JavaScript 中的異步編程
- 37.異步編程的 Promise
- 38.異步函數
- IX.更多標準庫
- 39.正則表達式(RegExp)
- 40.日期(Date)
- 41.創建和解析 JSON(JSON)
- 42.其余章節在哪里?