javascript中iterator通过实现[symbol.iterator]协议实现统一遍历,而非依赖类型系统;需运行时判断值类型并递归委托,配合typescript类型守卫可提升开发体验。

JavaScript 中 Iterator 本身不直接支持联合类型或多态集合的“统一遍历接口”,因为 JS 没有编译期类型系统,也没有原生的泛型或接口约束。但你可以通过约定 + 实现 [Symbol.iterator] 方法,在运行时达成行为上的一致遍历能力——关键不是类型层面的统一,而是协议层面的统一。
让任意对象支持 for...of:实现 Symbol.iterator
只要一个对象拥有可调用的 [Symbol.iterator] 方法,且该方法返回符合迭代器协议的对象(即有 next() 方法,返回 { value, done }),它就能被 for...of、...spread、Array.from() 等消费。
例如,你有一个混合了字符串、数字、数组的“多态集合”:
const mixedCollection = {
items: ["hello", 42, [1, 2], { x: 1 }],
*[Symbol.iterator]() {
for (const item of this.items) {
if (Array.isArray(item)) {
yield* item; // 展开数组
} else if (typeof item === "string") {
yield ...item; // 展开字符串字符(可选)
} else if (item && typeof item[Symbol.iterator] === 'function') {
yield* item; // 递归委托给其他可迭代对象
} else {
yield item;
}
}
}
};
<p>for (const val of mixedCollection) {
console.log(val); // "h", "e", "l", "l", "o", 42, 1, 2, {x: 1}
}</p>联合类型的“统一遍历”靠运行时判断,而非类型声明
TypeScript 的联合类型(如 string | number | string[])只在编译期起作用,运行时不存在。所以“统一遍历”的实现逻辑必须基于值的实际结构做判断:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
Array.isArray()区分数组 - 用
typeof判断基础类型("string","number","object"等) - 检查
item[Symbol.iterator]是否为函数,决定是否可展开(安全委托) - 对 null/undefined 做显式跳过,避免意外错误
封装可复用的多态迭代器工厂
把上述逻辑抽成函数,便于在不同集合中复用:
function createFlatIterator(items) {
return {
*[Symbol.iterator]() {
for (const item of items) {
if (item == null) continue;
if (typeof item === "string" || Array.isArray(item)) {
yield* item;
} else if (item && typeof item[Symbol.iterator] === "function") {
yield* item;
} else {
yield item;
}
}
}
};
}
<p>// 使用
const data = ["a", [1, 2], 3, new Set(["x", "y"])];
const iteratable = createFlatIterator(data);</p><p>for (const x of iteratable) {
console.log(x); // "a", 1, 2, 3, "x", "y"
}</p>与 TypeScript 类型配合:用类型守卫提升开发体验
虽然运行时靠判断,但你可以用 TypeScript 类型守卫 + JSDoc 或内联类型标注,让编辑器理解你的迭代器产出什么:
/**
* @template T
* @param {T[]} items
* @returns {{ [Symbol.iterator](): Iterator<t extends any t : never> }}
*/
function createLooseIterator(items) {
return {
*[Symbol.iterator]() {
for (const item of items) {
if (Array.isArray(item)) yield* item;
else yield item;
}
}
};
}</t>这样在支持 TS 的环境中,for (const v of createLooseIterator([1, ["a", "b"]])) 的 v 会被推导为 number | string,实现“类型层面的联合感知”。
不复杂但容易忽略:统一遍历的本质是遵守迭代器协议,而不是依赖语言级的多态机制。你控制 next() 的输出逻辑,就控制了“怎么被遍历”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










