要让普通业务实体对象支持for...of循环,需定义[Symbol.iterator]方法并返回符合迭代器协议的对象;明确遍历目标(如属性值、内部数组等)后,在对象上实现该方法,返回含next()的迭代器。

要让普通业务实体对象支持 for...of 循环,关键是在该对象上定义 [Symbol.iterator] 方法,返回一个符合迭代器协议的对象(即有 next() 方法,且每次调用返回 { value, done } 形式的对象)。
明确迭代目标:你想遍历什么?
业务对象通常不是数组,没有天然顺序。先想清楚:是遍历它的属性名、属性值、某个内部数组字段,还是按某种业务逻辑生成的数据序列?例如:
- 用户对象
user = { id: 1, name: 'Alice', role: 'admin' }—— 可能想遍历可枚举属性值; - 订单对象
order.items是个数组 —— 可直接代理遍历items; - 分页结果对象
PageResult { list: [...], total: 100 }—— 可能只遍历list。
实现 [Symbol.iterator] 方法
在对象上设置 [Symbol.iterator] 属性,值为一个函数,该函数返回迭代器对象。最简可行示例:
const user = {
id: 1,
name: 'Alice',
role: 'admin',
[Symbol.iterator]() {
const keys = Object.keys(this);
let index = 0;
return {
next() {
if (index < keys.length) {
const key = keys[index++];
return { value: this[key], done: false };
}
return { value: undefined, done: true };
}.bind(this)
};
}
};
for (const val of user) {
console.log(val); // 1 → 'Alice' → 'admin'
}
注意:next 中需用 .bind(this) 或改用箭头函数/闭包,确保能访问到原始对象。
更健壮的写法:复用 Array.prototype.values()
避免手动管理索引和状态,可把目标数据转为数组再借用其迭代器:
const order = {
id: 1001,
items: ['book', 'pen', 'notebook'],
status: 'shipped',
[Symbol.iterator]() {
return this.items[Symbol.iterator]();
}
};
for (const item of order) {
console.log(item); // 'book' → 'pen' → 'notebook'
}
这种写法简洁、可靠,适用于目标字段本身可迭代(如数组、Set、Map 等)的场景。
支持多次遍历与状态隔离
每次调用 [Symbol.iterator]() 都应返回**新迭代器**,否则多个 for...of 同时使用会互相干扰。错误示范:
// ❌ 错误:共享同一个迭代器实例
const badObj = {
data: [1, 2, 3],
iterator: null,
[Symbol.iterator]() {
if (!this.iterator) {
this.iterator = this.data[Symbol.iterator]();
}
return this.iterator; // 所有调用都返回同一个
}
};
✅ 正确做法:每次调用都新建迭代器:
const goodObj = {
data: [1, 2, 3],
[Symbol.iterator]() {
return this.data[Symbol.iterator](); // 每次都 new 一个
}
};
只要返回符合协议的迭代器对象,业务对象就能自然融入 JavaScript 的迭代生态,for...of、扩展运算符([...obj])、解构([a, b] = obj)等都会自动生效。

















