什么是javascript迭代器_如何自定义可迭代对象?

迭代器是拥有next()方法并返回{value, done}对象的规范对象;可迭代对象需实现[Symbol.iterator]方法,返回合法迭代器,且该方法不能为箭头函数。

JavaScript 迭代器本身不是一种类型,而是遵循 next() 方法规范的对象;自定义可迭代对象的关键,在于让对象拥有一个返回迭代器的 [Symbol.iterator] 方法。

迭代器对象长什么样?

一个合法的迭代器对象必须有 next() 方法,该方法返回形如 { value: any, done: boolean } 的对象。一旦 donetruevalue 可省略(但建议显式设为 undefined)。

常见错误:直接返回 { value: x } 而漏掉 done 字段,导致 for...of 无限循环或报错。

const iterator = {
  next() {
    return { value: 'hello', done: false }; // ❌ 不终止
  }
};
// for (const x of iterator) {} // 会卡死

如何让普通对象变成可迭代的?

只需在对象上定义 [Symbol.iterator] 方法,且该方法返回一个符合迭代器协议的对象。

立即学习“Java免费学习笔记(深入)”;

  • 该方法必须是函数,不能是箭头函数(否则无法用 this 访问原对象)
  • 返回的迭代器通常需维护内部状态(如索引、游标),避免多次遍历时相互干扰
  • 若对象数据是静态数组,可复用 Array.prototype[Symbol.iterator]
const myCollection = {
  items: ['a', 'b', 'c'],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.items.length) {
          return { value: this.items[index++], done: false };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};

for (const item of myCollection) {
  console.log(item); // 'a' 'b' 'c'
}

for...of 和扩展运算符怎么触发迭代?

它们底层都会尝试调用对象的 [Symbol.iterator] 方法。如果没找到,会抛出 TypeError: X is not iterable

注意点:

  • Array.from(myCollection) 同样依赖该方法
  • MapSetStringTypedArray 等内置类型已实现,无需手动添加
  • 普通对象(plain object)默认不可迭代,即使有 length 或数字键也不行
const plainObj = { 0: 'x', 1: 'y', length: 2 };
// for (const x of plainObj) {} // TypeError!
// 必须显式添加 [Symbol.iterator] 才能支持

用生成器函数简化自定义迭代器

手写 next() 容易出错,推荐用 function* 生成器函数——它自动返回符合协议的迭代器。

优势:

  • 状态由引擎维护,不用手动存 index
  • 支持 yield 暂停/恢复,逻辑更直观
  • 可配合异步(async function*)做异步迭代(需搭配 for await...of
const counter = {
  from: 1,
  to: 3,
  *[Symbol.iterator]() {
    for (let i = this.from; i <= this.to; i++) {
      yield i;
    }
  }
};

console.log([...counter]); // [1, 2, 3]

真正容易被忽略的是:每次调用 [Symbol.iterator] 都应返回**新迭代器实例**。如果返回同一个对象,多个 for...of 循环会互相干扰——这是调试时最隐蔽的状态 bug 来源之一。