要使自定义对象支持扩展运算符,必须部署Symbol.iterator方法使其符合可迭代协议;该方法需返回含next()的迭代器对象,next()返回{value, done}结构,且普通对象因无原生Symbol.iterator而默认不可遍历。

要在自定义对象上支持扩展运算符(...)遍历,关键不是“让对象本身可遍历”,而是让它**符合可迭代协议(iterable protocol)**——即部署 Symbol.iterator 方法,返回一个符合迭代器协议的对象(含 next() 方法)。扩展运算符、for...of、解构赋值等都会自动调用这个接口。
为什么普通对象默认不支持扩展运算符?
Object 没有原生 Symbol.iterator 属性,因为属性顺序不保证,无法定义统一的遍历次序。扩展运算符遇到非可迭代对象会报错:TypeError: object is not iterable。
手动部署 Symbol.iterator 的核心步骤
给对象添加一个名为 [Symbol.iterator] 的方法,该方法必须返回一个**迭代器对象**(即具有 next() 方法的对象),且每次调用 next() 返回形如 { value: ..., done: true|false } 的结果。
- 明确你要遍历什么:是对象自身的可枚举属性名?属性值?键值对?还是按特定数组顺序?
- 在对象上定义
[Symbol.iterator]方法,内部维护遍历状态(如索引或指针) -
next()方法需按需返回当前项,并在结束后返回{ value: undefined, done: true }
常见部署方式示例
① 遍历自身可枚举属性值(类似 Object.values)
立即学习“Java免费学习笔记(深入)”;
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
const obj = {
a: 1,
b: 2,
c: 3
};
obj[Symbol.iterator] = function* () {
for (let key of Object.keys(this)) {
yield this[key];
}
};
console.log([...obj]); // [1, 2, 3]② 遍历键值对(类似 Object.entries)
obj[Symbol.iterator] = function* () {
for (let key of Object.keys(this)) {
yield [key, this[key]];
}
};
console.log([...obj]); // [['a', 1], ['b', 2], ['c', 3]]③ 基于固定数组顺序(更可控,推荐用于结构化数据)
const person = {
name: 'Alice',
age: 30,
city: 'Beijing',
[Symbol.iterator]() {
const keys = ['name', 'age', 'city'];
let index = 0;
return {
next: () => {
if (index < keys.length) {
return { value: this[keys[index++]], done: false };
}
return { value: undefined, done: true };
}
};
}
};
console.log([...person]); // ['Alice', 30, 'Beijing']注意事项
避免在 Symbol.iterator 中直接返回数组的迭代器(如 Array.prototype[Symbol.iterator].call(...)),除非你确保对象“类数组”且有 length 和数字键;否则易出错或行为不可预期。
Generator 函数(function*)是最简洁的实现方式,它自动满足迭代器协议,无需手动写 next 和状态管理。
如果对象继承自某个原型,也可在原型上部署 Symbol.iterator,所有实例都将继承该能力。

















