JavaScript的可迭代协议是对象需拥有[Symbol.iterator]方法并返回符合迭代器协议的对象;该方法必须为普通函数,返回含next()且返回{value,done}的对象。
可迭代协议不是语法糖,也不是新特性,而是 JavaScript 引擎识别“能被 for...of、Array.from()、展开运算符 [...obj] 等消费”的一套约定:对象必须有名为 [Symbol.iterator] 的方法,且该方法返回一个符合迭代器协议的对象(即有 next() 方法,返回 { value, done } 形状的对象)。
for...of 的最简写法直接在对象上定义 [Symbol.iterator] 方法即可。注意:不能用箭头函数(会丢失 this 绑定),且返回值必须是迭代器对象。
const obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]() {
const keys = Object.keys(this);
let index = 0;
return {
next() {
if (index < ke
ys.length) {
const key = keys[index++];
return { value: this[key], done: false };
}
return { value: undefined, done: true };
}.bind(this)
};
}
};
for (const val of obj) {
console.log(val); // 1, 2, 3
}
[Symbol.iterator] 是固定键名,必须用方括号计算属性写法next() 必须返回 { value, done },done: true 后不可再返回有效值this[key] 换成 key 即可function* 简化实现手写 next() 容易出错,生成器函数自动满足迭代器协议,是最推荐的方式。
const obj = {
x: 10,
y: 20,
z: 30,
*[Symbol.iterator]() {
for (const key of Object.keys(this)) {
yield this[key];
}
}
};
console.log([...obj]); // [10, 20, 30]
console.log(Array.from(obj)); // [10, 20, 30]
*,且内部用 yield 返回每个值this 指向调用对象,无需手动 bind
for...of 还是报错?即使加了 [Symbol.iterator],仍可能失败,原因很具体:
[Symbol.iterator] 方法抛出异常(比如访问了 undefined 的属性)→ 直接 TypeError: obj is not iterable
next 方法 → 同样报 is not iterable
this[Symbol.iterator] = function(){...}),但没在构造函数里执行,导致原型链上无该方法Object.assign({}, obj) 后,[Symbol.iterator] 不会被复制(Symbol 属性默认不可枚举,Object.assign 只拷贝可枚举自有属性)调试时可直接检查:typeof obj[Symbol.iterator] 是否为 "function",再手动调用 obj[Symbol.iterator]().next() 看返回结构是否合规。