JavaScript中实现带自定义过滤条件的集合迭代,核心是返回符合Iterator协议的对象,推荐用生成器函数(function*)简洁实现过滤逻辑,也可手动实现Iterator接口或封装为支持for...of的Iterable类。

JavaScript 中实现带自定义过滤条件的集合迭代,核心是返回一个符合 Iterator 协议的对象(即有 next() 方法并返回 { value, done } 形式的对象),同时在 next() 内部应用过滤逻辑,跳过不满足条件的元素。
用生成器函数最简洁地实现过滤迭代器
生成器函数(function*)天然返回可迭代对象,内部可用 yield 逐个输出符合条件的值,代码清晰、语义明确。
- 遍历原始数据时,对每个元素调用过滤函数
predicate - 只对
predicate(item) === true的元素执行yield - 无需手动管理索引或状态,引擎自动处理迭代暂停与恢复
示例:
function* filterIterator(array, predicate) {
for (const item of array) {
if (predicate(item)) yield item;
}
}
<p>// 使用
const numbers = [1, 2, 3, 4, 5, 6];
const evenIterator = filterIterator(numbers, x => x % 2 === 0);</p><p>console.log(evenIterator.next()); // { value: 2, done: false }
console.log(evenIterator.next()); // { value: 4, done: false }
console.log(evenIterator.next()); // { value: 6, done: false }
console.log(evenIterator.next()); // { value: undefined, done: true }
手动实现 Iterator 接口支持任意数据源
当需要更精细控制(如支持异步、惰性求值、或非数组类集合)时,可手动构造一个对象,实现 [Symbol.iterator]() 方法并返回具 next() 的迭代器。
立即学习“Java免费学习笔记(深入)”;
- 保存当前索引和原始数据引用
- 在
next()中循环查找下一个匹配项,避免提前计算全部结果 - 注意边界:遍历完后始终返回
{ done: true }
示例(支持类数组或可迭代对象):
function createFilterIterator(iterable, predicate) {
const iterator = iterable[Symbol.iterator]();
let nextResult = iterator.next();
<p>return {
[Symbol.iterator]() { return this; },
next() {
while (!nextResult.done) {
if (predicate(nextResult.value)) {
const value = nextResult.value;
nextResult = iterator.next();
return { value, done: false };
}
nextResult = iterator.next();
}
return { value: undefined, done: true };
}
};
}</p><p>// 使用
const filtered = createFilterIterator(['a', 'bb', 'c', 'ddd'], s => s.length > 1);
for (const s of filtered) console.log(s); // 'bb', 'ddd'
封装成可复用的 Iterable 类(支持 for...of 和扩展运算符)
让自定义过滤器像原生数组一样被 for...of、[...filtered] 或 Array.from() 消费,只需在类上部署 [Symbol.iterator] 方法。
- 构造时传入数据源和过滤函数
-
[Symbol.iterator]返回一个新生成器或手动迭代器,确保每次迭代独立 - 避免共享内部状态,防止多次遍历时相互干扰
示例:
class FilteredIterable {
constructor(source, predicate) {
this.source = source;
this.predicate = predicate;
}
<p>*[Symbol.iterator]() {
for (const item of this.source) {
if (this.predicate(item)) yield item;
}
}
}</p><p>// 使用
const words = new FilteredIterable(['hello', 'hi', 'world', 'bye'], w => w.length > 3);
console.log([...words]); // ['hello', 'world']
for (const w of words) console.log(w); // 'hello', 'world'
注意事项与常见陷阱
实际使用中需留意几个关键点,否则容易出现空结果、无限循环或意外提前终止。
- 过滤函数不应有副作用:比如修改外部变量或依赖闭包中的可变状态,否则多次迭代行为不一致
-
空或无效数据源要兼容:确保
source[Symbol.iterator]存在,必要时加typeof source[Symbol.iterator] === 'function'判断 -
惰性 vs 预计算:生成器是惰性的,适合大数据流;若需缓存结果,应在外部用
Array.from()或展开收集 - 与 Array.prototype.filter 的区别:后者立即创建新数组,前者不产生中间数组,内存友好且支持无限序列(如生成器链)


















