es-toolkit 的 Map.filter 函数:用谓词函数高效过滤 Map 集合
2026/9/17 5:17:40 网站建设 项目流程

es-toolkit 的 Map.filter 函数:用谓词函数高效过滤 Map 集合

【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit

filter是 es-toolkit 在es-toolkit/map子路径下提供的 Map 专用过滤函数:它接收一个Map和一个谓词回调,返回一个仅包含满足条件条目的全新 Map,且不修改原 Map。本文将以官方参考文档 docs/ja/reference/map/filter.md 为主体,结合仓库内 filter.ts 源码与 filter.spec.ts 测试用例,完整讲解它的 API、用法、实现原理与边界行为,读完即可在自己的 TypeScript 项目中安全使用。

函数签名与核心概念

filter的调用形态非常简洁:

const filtered = filter(map, callback);

它的作用是基于一个"谓词函数"(predicate function)对Map进行过滤:遍历 Map 的每一个条目,把条目交给回调函数测试,只有回调返回true的条目才会被保留。最终返回的是一个新的Map,原 Map 不会被修改。

参数说明

参数类型说明
mapMap<K, V>要进行过滤的 Map。
callback(value: V, key: K, map: Map<K, V>) => boolean测试每个条目的谓词函数。

返回值

  • Map<K, V>:仅包含满足谓词条件的条目的新 Map。

回调函数的三个参数依次为:当前条目的value)、key)以及原始 Map 本身map)。这意味着你既可以根据值过滤,也可以根据键过滤,甚至可以根据原始 Map 的某些整体状态(如map.size)来做判断。

基本用法

最简单也最常见的场景是根据值的大小进行过滤。例如从一个数字映射中筛选出所有大于 2 的值:

import { filter } from 'es-toolkit/map'; const map = new Map([ ['a', 1], ['b', 2], ['c', 3], ['d', 4], ]); const result = filter(map, value => value > 2); // 结果: // Map(2) { // 'c' => 3, // 'd' => 4 // }

注意这里必须从es-toolkit/map导入filter,而不是从es-toolkit主入口导入。原因在参考文档的提示框中有明确说明:为了避免与其他集合类型的同名函数发生潜在冲突,该函数仅能通过es-toolkit/map单独使用。这一设计在仓库的导出结构中得到印证:主入口 src/index.ts 只导出 array、function、math、object、predicate、promise、string、util 等模块,Map 相关的filtereverysome等函数统一收敛在 src/map/index.ts 中,而./map子路径映射定义在 package.json 的exports字段中。

按多种标准过滤

filter的回调可以基于任意条件组合进行判断,参考文档给出了两个典型例子。

按值的类型或属性过滤

当 Map 的值是对象时,可以直接访问对象的属性:

import { filter } from 'es-toolkit/map'; const inventory = new Map([ ['apple', { quantity: 10, inStock: true }], ['banana', { quantity: 0, inStock: false }], ['orange', { quantity: 5, inStock: true }], ]); const inStockItems = filter(inventory, item => item.inStock); // 结果: 包含 'apple' 和 'orange' 条目的 Map

按键的模式过滤

回调的第二个参数是键(key),因此可以用startsWith、正则等字符串方法做键的匹配:

import { filter } from 'es-toolkit/map'; const data = new Map([ ['user_1', 'Alice'], ['admin_1', 'Bob'], ['user_2', 'Charlie'], ]); const users = filter(data, (value, key) => key.startsWith('user_')); // 结果: 包含 'user_1' 和 'user_2' 条目的 Map

同时基于键与值过滤

谓词函数同时收到键和值,因此可以把两者组合起来做更精细的筛选:

const map = new Map([ ['apple', 5], ['banana', 3], ['cherry', 8], ['date', 2], ]); const result = filter(map, (value, key) => key.length > 5 && value > 2); // 结果: Map { 'banana' => 3, 'cherry' => 8 }

这个用例与 filter.spec.ts 中的 "should filter based on both key and value" 测试完全一致,说明文档示例与实现行为是严格对齐的。

源码级实现解析

filter的完整实现位于 src/map/filter.ts,整个函数只有十几行,核心逻辑如下:

export function filter<K, V>(map: Map<K, V>, callback: (value: V, key: K, map: Map<K, V>) => boolean): Map<K, V> { const result = new Map<K, V>(); for (const [key, value] of map) { if (callback(value, key, map)) { result.set(key, value); } } return result; }

从实现上可以提炼出几个关键行为:

  • 纯函数、无副作用:函数内部首先new Map()创建一个全新的结果容器,遍历过程只读取原 Map,从不调用set/delete等修改操作,因此原 Map 始终保持不变。测试用例 "should not modify the original Map"(filter.spec.ts)专门验证了过滤前后原 Map 的size与条目序列完全一致。
  • 时间复杂度为 O(n):通过for...of对 Map 做一次线性扫描,每次迭代调用一次回调,整体是标准的线性遍历,性能开销与 Map 大小成正比。
  • 回调的第三个参数是原始 Map 引用:实现中callback(value, key, map)直接传入原始 Map。测试用例 "should pass the original map to the predicate function" 验证了回调拿到的originalMap与传入的map是同一个对象引用(toBe断言),并演示了利用map.size做过滤的用法。
  • 泛型保持类型安全:函数签名为filter<K, V>,键类型K与值类型V会从传入的 Map 自动推断,返回值类型同样为Map<K, V>,过滤后不会丢失类型信息。

边界行为与测试佐证

filter.spec.ts 用一组全面的测试用例固定了该函数在各种边界条件下的行为,这些行为可以直接作为使用时的预期参考:

场景行为对应测试用例
无条目满足条件返回空Map"should return an empty Map when no entries match"
全部条目满足条件返回包含全部条目的新 Map(内容与原 Map 相等)"should return all entries when all match the predicate"
传入空 Map返回空Map,不抛异常"should handle an empty Map"
数字键回调中key为数字,可直接参与运算(如key % 2 === 0"should work with number keys"
复杂对象值可组合多个对象属性作为谓词条件"should work with complex predicates"
布尔值可精确匹配value === true"should handle boolean values"
键值组合条件同时使用keyvalue过滤"should filter based on both key and value"

这些测试不仅覆盖了文档中的示例,还额外验证了空 Map、全命中、全不命中以及数字键等容易被忽略的边界场景,说明该函数的行为是经过充分定义且稳定的。从 es-toolkit 的项目理念来看,这类工具函数追求"现代实现 + 强类型注解 + 高测试覆盖率",filter正是这一设计目标的缩影。

注意事项与最佳实践

  1. 导入路径:务必使用import { filter } from 'es-toolkit/map',不要尝试从es-toolkit主入口导入。这是为了规避与数组等其他集合类型同名过滤函数之间的命名冲突而做的刻意设计(见 package.json 的./map导出映射)。
  2. 返回值是新 Map:过滤结果是全新对象,与原 Map 没有引用关系,可以放心对结果做进一步增删改而不会污染原始数据。
  3. 回调不要产生副作用:虽然回调会拿到原始 Map 引用,但修改原 Map 会导致过滤过程不可预测,应保持谓词函数纯净(只做判断、不修改集合)。
  4. 保留条目顺序filter按 Map 的插入顺序遍历并依次set到结果中,因此结果的条目顺序与原 Map 一致,在依赖顺序的场合可以放心使用。
  5. TypeScript 自动推断:得益于泛型签名,传入Map<string, number>后,回调的value会被推断为numberkey被推断为string,无需手动标注类型。

如果你还需要对整个 Map 做"全部满足"或"存在满足"的判断,可以参考同目录下 every.ts、some.ts 等函数,它们与filter共享相同的回调签名约定,组合使用可以覆盖 Map 数据筛选的大部分需求。

【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询