普通对象不能直接用 for...of 遍历,根本原因在于它没有实现可迭代协议,即缺少有效的 symbol.iterator 方法;该方法需返回符合迭代器协议的对象,而 object.prototype 上此属性为 undefined,导致 for...of 无法启动迭代流程。

普通对象不能直接用 for...of 遍历,根本原因在于它没有实现可迭代协议(Iterable Protocol),也就是缺少一个有效的 [Symbol.iterator] 方法。这不是 bug,而是语言设计的明确取舍。
普通对象默认没有 [Symbol.iterator] 方法
JavaScript 规定:只有实现了可迭代协议的对象,才能被 for...of、扩展运算符([...obj])、Array.from() 或解构赋值等语法使用。该协议要求对象必须拥有一个名为 Symbol.iterator 的属性,且这个属性是一个无参函数,调用后返回一个符合迭代器协议(Iterator Protocol)的对象。
查看常见类型原型上的表现:
-
Array.prototype[Symbol.iterator]→ 返回ƒ values() { [native code] } -
Map.prototype[Symbol.iterator]→ 返回ƒ entries() { [native code] } -
Object.prototype[Symbol.iterator]→undefined
也就是说,普通对象(如 {a: 1, b: 2})在创建时,其自身和原型链上均不提供 [Symbol.iterator],因此引擎在执行 for (let v of obj) 时,会立即报错:TypeError: obj is not iterable。
for...of 的底层执行依赖两个协议
for...of 不是“按顺序读属性”,而是一套标准化协作机制:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 第一步:调用
obj[Symbol.iterator](),获取一个迭代器对象 - 第二步:反复调用该迭代器的
next()方法,每次返回形如{ value, done }的对象 - 第三步:只要
done为false,就将value绑定给循环变量,并继续;一旦done为true,循环终止
普通对象缺失的是第一步——它连“产出迭代器”的能力都没有,后续步骤自然无法启动。
为什么语言不给对象默认加上 [Symbol.iterator]?
这不是遗漏,而是有意为之的设计决策:
- 语义模糊:对象的属性本质是无序键值对(即使 ES2015+ 规定了枚举顺序,那也只是遍历行为规范,不等于天然具备“序列”语义)
-
用途分离:对象的核心职责是结构化存储与属性访问,
for...in和Object.keys()已覆盖其典型遍历需求 -
避免歧义:如果默认迭代返回键?值?还是
[key, value]?不同场景需要不同结果,强行统一反而引发误用
想让对象支持 for...of,可以手动补全
你不需要修改语言,只需在对象上定义 [Symbol.iterator],返回一个带 next() 的对象即可。常用方式有:
- 用生成器函数(推荐):简洁、自动维护状态,例如
function* () { yield* Object.entries(this); } - 手写迭代器对象:显式管理索引和结束条件,适合定制逻辑(如跳过某些属性、按特定顺序返回)
- 避免污染
Object.prototype:全局添加会影响所有对象,易引发冲突;应只在具体对象或类实例上定义
例如,让 {x: 10, y: 20} 支持 for (let [k, v] of obj),只需一行:
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










