iterator.prototype.filter 惰性执行,不创建中间数组,仅按需处理元素;而数组 filter 立即遍历并存储全部匹配项,易致内存暴增,尤其在大数据或流式场景下。

Iterator.prototype.filter 不创建中间数组,也不预加载全部数据 —— 它返回一个新迭代器,每次调用 next() 时才检查当前项是否满足条件。真正需要哪一项,才处理哪一项。这对超大型或无限数据集(比如日志流、实时传感器数据、数据库游标)极为关键:内存只占用单个元素的空间,而非整个集合。
为什么传统 filter() 会吃光内存
对数组直接调用 .filter() 会立即遍历全部元素,分配新数组存下所有匹配项。哪怕你最后只取前 3 条:
-
[...hugeArray].filter(x => x > 1000).slice(0, 3)—— 先建一个可能含百万项的新数组,再切片 - 原始数组 + 中间数组 + 最终子数组,三重内存压力
- 若数据源是生成器或异步流,还可能触发提前耗尽或阻塞
正确用法:用 values() 转成迭代器再链式 filter
只要对象可迭代(Array、Set、Map、Generator 等),就能走惰性路径:
- 数组过滤:
arr.values().filter(x => x % 2 === 0) - Map 值过滤:
myMap.values().filter(v => typeof v === 'string') - 生成器过滤:
function* numbers() { for (let i = 0; i x % 7 === 0) - 配合 take() 控制数量:
data.values().filter(x => x.active).take(50).toArray()—— 只处理前 50 个匹配项
搭配 for...of 或手动 next 按需消费
不转数组也能安全使用,避免一次性加载:
- 循环打印前 10 个偶数:
for (const n of Array.from({ length: 1000000 }).keys().filter(x => x % 2 === 0)) { if (--count - 手动控制:
const iter = largeGen().filter(x => x > 1e6); let result = []; for (let i = 0; i - 注意:错误会在首次
next()时抛出,便于定位问题源头
兼容性与避坑提醒
该方法已在 Chrome 124+、Firefox 125+、Node.js 20.12+ 原生支持,无需 polyfill:
- 确保源对象有
Symbol.iterator,且next()返回符合协议的对象 - 不支持异步函数作为 filter 回调;如需 await,请改用
AsyncIterator相关提案 - filter 内部抛错会中断迭代,适合强校验场景;若要跳过异常项,需在外层 try/catch 包裹映射逻辑










