要让原始业务对象支持解构赋值和扩展运算符,需在其上部署symbol.iterator方法使其成为可迭代对象;因普通对象默认无该方法,故[...obj]会报错,而数组等内置类型已实现;可通过生成器函数自定义迭代逻辑,如按字段顺序、过滤空值或敏感字段等。

要让原始业务对象支持解构赋值和扩展运算符,关键是在对象上部署 Symbol.iterator 方法,使其成为可迭代对象。JavaScript 的解构赋值(如 const [a, b] = obj)和扩展运算符(如 [...obj])底层都会调用该对象的 @@iterator 方法。原生对象(如 Object)默认不可迭代,因此需手动实现。
为什么普通对象不支持解构和扩展?
因为普通对象没有定义 Symbol.iterator,所以 [...obj] 会报错 TypeError: obj is not iterable。数组、字符串、Map、Set 等内置类型已内置该接口;而 plain object 没有,这是设计使然——对象是键值对集合,语义上不天然有序,无法明确“依次遍历什么”。但业务中常需按某种逻辑(如字段值、特定属性顺序、或过滤后值)生成序列,这时就需自定义迭代行为。
实现 Symbol.iterator 的基本写法
只需在对象上添加一个返回迭代器对象的方法,该方法名是 Symbol.iterator,返回的对象必须有 next() 方法,每次调用返回 { value, done } 形式的结果。
常见做法是返回一个生成器函数(function*),它自动满足迭代器协议:
const user = {
id: 101,
name: '张三',
role: 'admin',
status: 'active'
};
<p>// 让它可被解构为 [id, name, role, status]
user[Symbol.iterator] = function* () {
yield this.id;
yield this.name;
yield this.role;
yield this.status;
};</p><p>// ✅ 现在可以解构
const [id, name, role] = user; // id=101, name='张三', role='admin'</p><p>// ✅ 也可用于扩展
console.log([...user]); // [101, '张三', 'admin', 'active']
</p>按需定制:只遍历值、键或特定字段
可根据业务需要灵活控制迭代内容。例如:
- 只遍历自有可枚举属性的值:
Object.values(this)+yield* - 按固定字段顺序输出:
['name', 'email', 'phone'].map(key => this[key]) - 跳过空值或敏感字段:
if (key !== 'password' && this[key] != null) yield this[key]
示例:仅输出非空、非 password 字段的值
user[Symbol.iterator] = function* () {
const keys = Object.keys(this);
for (const key of keys) {
if (key === 'password') continue;
if (this[key] == null) continue;
yield this[key];
}
};
注意事项与边界情况
注意以下几点避免踩坑:
-
Symbol.iterator是方法,不是属性值;必须是函数(最好是生成器),不能直接赋值为数组 - 解构赋值时,左侧变量个数超过迭代次数,多余变量得
undefined;少于则忽略后续项 - 若业务对象是类实例,推荐在原型上定义
Symbol.iterator,避免每个实例重复创建函数 - 扩展运算符
[...obj]仅适用于可迭代对象,不会展开对象自身属性(那是{...obj}的职责)
类中写法示例:
class User {
constructor(id, name, role) {
this.id = id;
this.name = name;
this.role = role;
}
}
User.prototype[Symbol.iterator] = function* () {
yield this.id;
yield this.name;
yield this.role;
};
<p>const u = new User(202, '李四', 'editor');
const [id, name] = u; // ✅ 正常工作
</p>











