什么是 Iterable 对象?与 Array 有什么区别?

探讨 JavaScript 中 Iterable 对象与 Array 的区别,包括定义方式、访问方式和遍历操作。通过理解这些差异,掌握如何在实际开发中选择使用。

JavaScript 中等 数据结构 Iterable 对象

在 JavaScript 中,Iterable 对象是指实现了 [Symbol.iterator] 方法的对象。这允许它们被迭代(如使用 for...of 循环遍历),因为该方法返回一个迭代器(Iterator)。迭代器是具有 next() 方法的对象,每次调用 next() 都返回一个形如 { value, done } 的接口值,表示当前迭代元素和是否结束。常见的 Iterable 对象包括:Array、String、Set、Map、TypedArray、NodeList,以及自定义实现[Symbol.iterator]的对象。

Array 是一种具体的集合类型,也实现了 Iterable 协议,但它们在本质和使用方式上有明显区别,主要体现在定义、访问、方法等方面。

1. 定义方式的不同

  • Array: 可直接通过字面量创建,例如 [1, 2, 3],简洁易用。
  • Iterable 对象: 需通过实现 [Symbol.iterator] 方法手动定义,例如:
    const iterableObject = {
    [Symbol.iterator]: function* () {
      yield 'one';
      yield 'two';
      yield 'three';
    }
    }; // 自定义迭代器通过 Generator 创建。
    

    这表示任何对象都可遵守 Iterable 协议成为可迭代的对象,并非只有内置集合。

2. 元素访问和修改方式

  • Array 的特性
    • 支持索引访问(如 arr)和直接修改元素(如 arr = 'new')。
    • 提供数组原生方法如 push, pop, slice,以便增删改元素。
      const arr = ['a', 'b'];
      console.log(arr); // 输出 'a'
      arr.push('c');      // 修改数组,扩展元素
      
  • Iterable 对象:
    • 不可直接通过索引访问或修改元素(因为没有定义数字索引,仅通过迭代器序列读取)。
    • 只支持顺序迭代访问,通常用于遍历只读序列,例如:
      const iterable = iterableObject; // 来自上方示例
      for (const value of iterable) {
      console.log(value); // 依次输出 'one', 'two', 'three'
      }
      const iter = iterable[Symbol.iterator]();
      console.log(iter.next().value); // 'one' - 每次调用 next() 获取下个元素。
      

3. 遍历和操作的适用性

  • 遍历方式差异:
    • Array:既可用 for...in(遍历索引/properties,但不安全,可能访问额外属性),也能用 for...of
    • Iterable:默认只适用 for...of 循环遍历元素的 value,避免了 for...in 中可能的属性意外问题。
  • 操作方法
    • Array 是独立的集合类型,有丰富的内置数组方法用于数据操作(如 filter, map)。
    • Iterable 只是协议,对象不一定有这些数组方法;如需集合操作,常需转换为 Array(如 Array.from()),而非直接操作。

4. 其他关键区别

  • 属性扩展影响
    • Array 添加属性会影响所有遍历方式(如添加额外属性会被 for...in 检出),而 Iterable 设计专一化于序列访问。
  • 抽象层级
    • Array 是实例级对象,代表一组有序元素。
    • Iterable 是更抽象的协议级概念,促进统一数据迭代机制,为 Array, Set, Map 等提供遍历能力标准化。

总结

简言之,Iterable 是 JavaScript 可迭代协议,任何对象都可遵守它成为可遍历序列;Array 则是实现了此协议的具体集合类型,提供额外操作方法。Array 是 Iterable 的一个特定实现,而 Iterable 对象并非总是类数组(如 Set)或能索引修改。实践中,为数据序列化访问优先选 Iterable;如需灵活元素的增删及索引,则依赖 Array。