JavaScript可通过实现[Symbol.iterator]接口为复合结构对象定制过滤遍历逻辑,核心是让对象可迭代并在生成器中递归展开、按predicate函数过滤各层级值。

JavaScript 中可以通过实现 [Symbol.iterator] 接口,为任意复合结构对象(如嵌套对象、数组、Map、Set 混合体)定制统一的过滤遍历逻辑。核心在于:**让对象可迭代 + 在迭代器中按需展开并过滤**。
定义支持混合结构的可迭代对象
先明确目标结构:比如一个包含数组、普通对象、null、字符串、数字、Map、Set 的“容器”:
例如:{ users: [{name:'a'}, {name:'b'}], config: new Map([['timeout', 5000]]), tags: new Set(['dev', 'js']), meta: null }
这类结构天然不具备统一遍历能力。要让它支持 for...of 和扩展运算符([...obj]),必须返回一个符合迭代器协议的对象(含 next() 方法)。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
在 Symbol.iterator 中递归展开并过滤
迭代器内部不只做“一层遍历”,而是深度遍历所有可枚举/可迭代子项,并根据自定义规则跳过不需要的值(如 null、undefined、空字符串、非对象/数组/Map/Set 的原始值等)。
- 用生成器函数
function*实现最简洁——自动处理暂停/恢复,天然适配yield递归 - 对每个属性值判断类型:
Array.isArray(val)、val instanceof Map、val instanceof Set、val && typeof val === 'object' - 对原始值(string/number/boolean)可选择性 yield(比如只保留非空字符串),或完全跳过
- 对 null/undefined/NaN 等直接 continue
添加过滤条件作为构造参数
把过滤逻辑抽离成可配置的 predicate 函数,让同一套迭代器支持不同场景:
- 构造时传入
filterFn,默认为(item) => item !== null && item !== undefined - 在 yield 前调用
filterFn(item),仅当返回 true 才产出 - 例如:只遍历所有字符串类型的叶子节点 →
filterFn: (x) => typeof x === 'string' && x.trim() - 例如:只取所有对象中的
name字段 →filterFn: (x) => x && typeof x === 'object' && 'name' in x
实际代码示例
以下是一个可直接运行的封装:
class CompositeIterable {<br> constructor(data, filterFn = (x) => x != null) {<br> this.data = data;<br> this.filterFn = filterFn;<br> }<br> *[Symbol.iterator]() {<br> function* walk(obj) {<br> if (obj == null) return;<br> if (Array.isArray(obj)) {<br> for (const item of obj) yield* walk(item);<br> } else if (obj instanceof Map || obj instanceof Set) {<br> for (const item of obj) yield* walk(item);<br> } else if (typeof obj === 'object') {<br> for (const key in obj) {<br> if (Object.hasOwn(obj, key)) yield* walk(obj[key]);<br> }<br> } else {<br> if (this.filterFn(obj)) yield obj;<br> }<br> }<br> yield* walk.call(this, this.data);<br> }<br>}
使用:
const mixed = new CompositeIterable({<br> users: [{name: 'Alice'}, {name: 'Bob'}],<br> tags: new Set(['js', 'web']),<br> config: null,<br> version: 2.1<br>}, x => typeof x === 'string');for (const str of mixed) console.log(str); // 'js', 'web'

















