Iterable

Iterable 是能提供默认迭代器的对象,是 for...of 和展开运算符的输入前提。

#type / concept #status / growing #resource / javascript #resource / ecmascript

[!info] related notes

Iterable

一句话定义

Iterable 是实现了 Symbol.iterator 方法的对象,该方法返回一个迭代器(Iterator),使得对象可以被 for...of、展开运算符等语法消费。

核心机制 / 工作原理

迭代协议:Iterable 与 Iterator

两个协议紧密关联但不同:

Iterable 协议(可迭代协议):

  • 对象必须实现 [Symbol.iterator]() 方法
  • 该方法返回一个 Iterator 对象

Iterator 协议(迭代器协议):

  • 返回的对象必须有 next() 方法
  • next() 返回 { value: any, done: boolean }
  • done: true 表示迭代结束
// 手动实现一个可迭代对象
const range = {
  from: 1,
  to: 5,
  [Symbol.iterator]() {
    let current = this.from
    const last = this.to
    return {
      next() {
        if (current <= last) {
          return { value: current++, done: false }
        }
        return { done: true }
      }
    }
  }
}

for (const num of range) {
  console.log(num)  // 1, 2, 3, 4, 5
}

内置可迭代对象

类型说明
Array最常见的可迭代对象
String字符串可按 Unicode 码点迭代
Map迭代 [key, value]
Set迭代每个元素
TypedArrayUint8ArrayFloat32Array
arguments函数参数列表
NodeListDOM 查询结果
ReadableStream流式数据(异步可迭代)

消费 iterable 的语法

const arr = [1, 2, 3]

// for...of
for (const item of arr) { }

// 展开运算符
const copy = [...arr]

// 解构赋值
const [a, b] = arr

// Array.from()
const doubled = Array.from(arr, x => x * 2)

// Map / Set 构造函数
const set = new Set(arr)

// Promise.all()
await Promise.all(arr.map(asyncFn))

自定义可迭代对象

使用生成器函数更简洁:

const range = {
  from: 1,
  to: 5,
  *[Symbol.iterator]() {
    for (let i = this.from; i <= this.to; i++) {
      yield i
    }
  }
}

// 现在 range 可以被 for...of 消费
[...range]  // [1, 2, 3, 4, 5]

生成器函数创建迭代器

function* fibonacci() {
  let a = 0, b = 1
  while (true) {
    yield a
    ;[a, b] = [b, a + b]
  }
}

// fibonacci() 返回一个既是迭代器又是可迭代对象的生成器
const fib = fibonacci()
fib.next()  // { value: 0, done: false }
fib.next()  // { value: 1, done: false }

// 生成器也是可迭代的
for (const n of fibonacci()) {
  if (n > 100) break
  console.log(n)  // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
}

最小例子

// 最简单的可迭代对象
const iterable = {
  [Symbol.iterator]() {
    let i = 0
    return {
      next: () => ({ value: i++, done: i > 3 })
    }
  }
}

[...iterable]  // [0, 1, 2]

与类数组对象的区别

维度Iterable类数组(Array-like)
定义实现了 Symbol.iteratorlength 属性和数字索引
能用 for...of不能(除非同时是 iterable)
能用展开运算符不能
转数组[...iterable]Array.from(arrayLike)
典型例子MapSetNodeListargumentsdocument.querySelectorAll
// 类数组但不是 iterable
const arrayLike = { 0: 'a', 1: 'b', length: 2 }
// for (const x of arrayLike) {} // TypeError!

// 转换方式
Array.from(arrayLike)  // ['a', 'b']

// NodeList 既是类数组又是 iterable
const nodes = document.querySelectorAll('div')
for (const node of nodes) { }  // 可以
[...nodes]  // 可以

边界与常见误解

  • 误解:有 length 就是可迭代的。 不是。length 只是类数组的特征,可迭代需要 Symbol.iterator
  • 误解:Object 是可迭代的。 普通对象 {} 不是 iterable,不能用 for...of。要用 Object.keys/values/entries
  • 误解:for...infor...of 一样。 for...in 遍历可枚举属性(含原型链),for...of 遍历 iterable 的值。
  • 边界:迭代器对象也可以是可迭代的。 如果迭代器的 next() 方法的对象同时实现了 Symbol.iterator(返回 this),它就是 both。生成器就是这种设计。
  • 边界:异步可迭代。 Symbol.asyncIterator + for await...of 处理异步数据流。

最短记忆方式

  • Symbol.iterator → 可迭代 → 能被 for...of 消费
  • Iterator:有 next() 返回 { value, done }
  • Iterable 不是 Iterator,但两者紧密关联
创建于 2026/4/7 更新于 2026/5/27