要让类数组对象支持自定义遍历,需实现[symbol.iterator]方法并返回符合迭代器协议的对象:每次调用next()返回{value, done},通过闭包维护独立状态,支持多次遍历及跳过、反向等定制逻辑。

要让一个类数组对象支持自定义遍历规则,关键不是把它“变成数组”,而是让它符合 JavaScript 的 可迭代协议(Iterable Protocol):即拥有 [Symbol.iterator] 方法,且该方法返回一个满足 迭代器协议(Iterator Protocol) 的对象——也就是有 next() 方法,每次调用返回 { value, done } 形式的对象。
明确类数组结构与遍历目标
类数组对象通常具备 length 属性和数字索引(如 0、1),但不继承 Array.prototype。例如:
你想控制它怎么被 for...of、扩展运算符([...myLikeArray])或 Array.from() 消费——比如只遍历偶数索引、跳过 null 值、反向遍历,或按某种计算顺序产出值。
在对象上实现 Symbol.iterator 方法
直接在对象上定义 [Symbol.iterator],返回一个迭代器对象。注意:这个迭代器应是“新鲜的”,每次调用都重置状态,才能支持多次遍历(如两次 for...of)。
- 用闭包保存独立状态(如当前索引
index),避免多个循环互相干扰 -
next()内部判断是否还有有效值;若无,返回{ done: true } - 若需跳过某些项(如
undefined或非数字索引),可在循环中主动index++并继续判断,不立即返回
示例:实现只遍历偶数索引的类数组对象
const evenIndexArray = {0: 'a',
1: 'skip',
2: 'b',
3: 'skip',
4: 'c',
length: 5,
[Symbol.iterator]() {
let index = 0;
const that = this;
return {
next() {
while (index if (index % 2 === 0 && index in that) {
const value = that[index];
index++;
return { value, done: false };
}
index++;
}
return { done: true };
}
};
}
};
console.log([...evenIndexArray]); // ['a', 'b', 'c']
用生成器函数简化实现
生成器函数(function*)天然返回符合迭代器协议的对象,写法更清晰、不易出错,也更适合复杂逻辑(如嵌套、异步、条件过滤)。
- 把遍历逻辑写在
yield语句中,JS 自动包装成next()行为 - 可轻松实现惰性求值:值只在需要时才计算,适合大数据或无限序列
- 支持
yield*委托其他可迭代对象,利于复用
等效上面的生成器写法:
evenIndexArray[Symbol.iterator] = function* () {for (let i = 0; i if (i in this) yield this[i];
}
};
确保支持常见消费方式
实现后,该对象就能被所有原生支持可迭代协议的语法正确使用:
for (const val of evenIndexArray) { ... }Array.from(evenIndexArray)[...evenIndexArray]console.log(...evenIndexArray)
但注意:Array.isArray(evenIndexArray) === false,它仍是普通对象;也不具备 push、map 等数组方法——这是预期行为,因为目标只是“可被遍历”,而非“是数组”。










