普通对象不能被for...of遍历,因其未实现symbol.iterator方法;可迭代对象需具备可调用的[symbol.iterator]属性,常见如array、map等;普通对象属性无序且语义不明确,故有意不实现该协议。

普通对象不能直接被 for...of 遍历,根本原因在于它不满足“可迭代对象”(Iterable)的定义。识别一个值是否为可迭代对象,关键看它是否实现了 可迭代协议——即拥有有效的 Symbol.iterator 方法。
如何快速判断一个对象是否可迭代
最直接的方式是检查该对象是否具有可调用的 [Symbol.iterator] 属性:
- 在控制台执行
obj[Symbol.iterator],若返回一个函数(如ƒ values() { [native code] }),说明它是可迭代的; - 若返回
undefined或非函数值(如null、string),则不可迭代; - 常见可迭代对象:
Array、String、Map、Set、TypedArray、arguments、NodeList、Generator; - 普通对象(
{}、{a:1, b:2})默认返回undefined,因此不是可迭代对象。
为什么普通对象没实现 Symbol.iterator
这不是遗漏,而是有意设计:
- 语义不明确:数组、字符串、Map 等天然有“成员序列”的概念,而普通对象的属性本质上是无序键值对(尽管 ES2015+ 规定了枚举顺序,但那属于遍历行为规范,不等于迭代语义);
-
用途分化清晰:对象的核心作用是结构化数据存储与属性访问,
for...in和Object.keys()已足够覆盖其遍历需求; - 避免歧义:如果默认迭代返回键、值还是键值对?不同场景需要不同结果,统一约定反而增加误解风险。
想用 for...of 处理对象,怎么办
不需要改语言规则,只需转换视角或补充协议:
- 用
Object.keys(obj)遍历键,Object.values(obj)遍历值,Object.entries(obj)遍历键值对——三者都返回数组,天然可迭代; - 手动添加
[Symbol.iterator]方法,自定义迭代逻辑(例如只返回值、按特定顺序返回、跳过某些属性等); - 注意:不建议污染
Object.prototype,容易引发冲突和意外行为;局部定义更安全。
本质上,for...of 不是“遍历所有东西的万能循环”,而是专为有明确迭代语义的数据结构设计的语法糖。理解这一点,就能自然区分它和 for...in、forEach 的边界。











