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

JavaScript 迭代器本身不是一种类型,而是遵循 next() 方法规范的对象;自定义可迭代对象的关键,在于让对象拥有一个返回迭代器的 [Symbol.iterator] 方法。
迭代器对象长什么样?
一个合法的迭代器对象必须有 next() 方法,该方法返回形如 { value: any, done: boolean } 的对象。一旦 done 为 true,value 可省略(但建议显式设为 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)同样依赖该方法 -
Map、Set、String、TypedArray等内置类型已实现,无需手动添加 - 普通对象(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 来源之一。











