JavaScript迭代器必须实现可调用的next()方法,返回{value, done}对象;可迭代对象需部署Symbol.iterator方法返回迭代器;for-of仅依赖该协议,不推测结构,错误即报错。

JavaScript 迭代器对象必须实现 next() 方法
迭代器是一个有状态的对象,核心是它必须带一个 next() 方法,每次调用返回形如 { value: any, done: boolean } 的对象。只要满足这个结构,哪怕手动构造,JS 就认它是迭代器。
常见错误是以为“有 next 属性就行”,但漏掉可调用性——next 必须是函数,否则 for-of 会报 TypeError: iterator.next is not a function。
-
done: true后再调用next(),仍应返回{ value: undefined, done: true }(规范要求) - 迭代器通常不重用:同一个迭代器对象多次用于
for-of,第二次会从上次暂停处继续,而非重头开始 - 手写时别忘了闭包保存内部状态(比如数组索引),否则多次调用会混乱
Symbol.iterator 是可迭代协议的入口点
一个对象要被 for-of、解构、Array.from() 等识别为“可迭代的”,必须在其原型链上提供 Symbol.iterator 方法,且该方法返回一个迭代器对象。
内置类型如 Array、String、Map、Set 都实现了它;普通对象默认没有,所以 for-of 直接遍历 plain object 会报错 TypeError: XXX is not iterable。
立即学习“Java免费学习笔记(深入)”;
- 自定义类可通过在原型或实例上定义
[Symbol.iterator]() { return ... }来支持迭代 - 箭头函数不能用作
Symbol.iterator方法,因为它没有this绑定,无法访问实例数据 - 如果
Symbol.iterator返回的不是迭代器(比如返回数字或null),for-of会立即抛TypeError
for-of 循环底层只做三件事
for-of 不关心数据结构是什么,只按固定流程执行:取迭代器 → 反复调用 next() → 检查 done → 提取 value。它不依赖 length、下标或键名。
const arr = [1, 2, 3];
const it = arr[Symbol.iterator]();
let result;
while (!(result = it.next()).done) {
console.log(result.value); // 依次输出 1, 2, 3
}
- 每次循环体执行前,自动调用一次
next();若done为true,循环终止 -
break或return退出时,引擎**不会**自动调用return()(即使迭代器有),这是容易被忽略的资源清理盲区 - 异步迭代器(
Symbol.asyncIterator)需用for-await-of,混用会静默失败或报错
字符串和类数组对象的迭代行为差异
字符串按 Unicode 码点迭代(正确处理 emoji 和代理对),而 arguments、NodeList 等类数组对象虽有 length 和数字键,但默认不可迭代——除非显式部署 Symbol.iterator(现代 DOM API 已补全 NodeList.prototype[Symbol.iterator])。
常见陷阱:用 Array.from(someNodeList) 能工作,是因为它内部检测到 Symbol.iterator;但直接 for-of someNodeList 在旧环境会失败。
- IE 完全不支持
Symbol.iterator,需用for循环 +length回退 -
Array.from({ length: 3 })返回[undefined, undefined, undefined],因为该对象无Symbol.iterator,Array.from改用length+undefined填充逻辑 - 手动让类数组可迭代,最简方式:
obj[Symbol.iterator] = Array.prototype[Symbol.iterator];(前提是它有合法的length和索引属性)
for-of 对协议的严格依赖——它既不推测结构,也不容错兜底。一旦 Symbol.iterator 缺失或 next() 返回格式错,就立刻崩,没商量。











