makeMap

栏目: source 发布时间:2025-10-13
function makeMap(
  str: string,
  expectsLowerCase?: boolean
): (key: string) => true | undefined {
  const map = Object.create(null)
  const list: Array<string> = str.split(',')
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
  }
  return expectsLowerCase ? val => map[val.toLowerCase()] : val => map[val]
}

这段代码定义了一个工厂函数 makeMap,用于创建高效的字符串匹配函数。其核心逻辑是将逗号分隔的字符串转换为键值映射对象,并返回一个闭包函数实现快速查找。以下是逐层解析:

1. 函数结构

function makeMap(
  str: string,
  expectsLowerCase?: boolean
): (key: string) => true | undefined {
  // 函数体
}
  • 输入参数
    • str:逗号分隔的字符串(如 "div,span,img"
    • expectsLowerCase(可选):是否不区分大小写(默认为 false
  • 输出:返回一个查找函数,接受字符串参数 key,返回 true(存在)或 undefined(不存在)

2. 内部实现逻辑

(1) 创建映射对象

const map = Object.create(null); // 创建无原型链的纯净对象
const list = str.split(',');    // 将输入字符串拆分为数组
for (let i = 0; i < list.length; i++) {
  map[list[i]] = true;          // 将数组元素作为对象键,值设为 true
}
  • 示例:若 str = "div,span,img",则 map = { div: true, span: true, img: true }
  • 优势:对象键查找的时间复杂度为 O(1),比数组 includes 更高效

(2) 返回闭包函数

return expectsLowerCase 
  ? val => map[val.toLowerCase()] // 不区分大小写
  : val => map[val];              // 区分大小写
  • 场景区分
    • expectsLowerCase = true 时:输入 val = "DIV" → 转换为 "div" → 查找 map
    • expectsLowerCase = false 时:直接用原始值 val 查找

3. 典型使用场景

(1) 标签白名单校验

const isHTMLTag = makeMap('div,span,img,p');
isHTMLTag('div');    // true
isHTMLTag('DIV');    // false(区分大小写)
isHTMLTag('header'); // undefined

(2) 不区分大小写匹配

const isCaseInsensitive = makeMap('div,span,img', true);
isCaseInsensitive('DIV'); // true
isCaseInsensitive('Span'); // true

(3) 框架/库内部优化

  • Vue/React 等框架用于快速判断合法标签、指令名
  • 构建工具(如 Vite/Webpack)校验文件扩展名
  • CLI 命令参数合法性校验

4. 性能与设计亮点

  • 空间换时间:预生成映射对象,避免重复遍历数组
  • 原型污染防护Object.create(null) 创建无原型对象,避免 toString/hasOwnProperty 等原生属性干扰
  • 闭包缓存:返回的函数复用已创建的 map 对象,减少内存开销
  • 返回值设计:返回 true 而非 Boolean 对象,利用 undefined 的假值特性简化调用方判断逻辑

5. 边界场景处理

  • 空字符串输入str = "" → 返回函数始终返回 undefined
  • 重复键处理:后出现的键会覆盖之前的值(如 "a,a"{ a: true }
  • 空白符问题:输入 "a, b" → 键为 " b"(含空格),需注意输入预处理

6. 对比原始实现的优势

若直接使用数组 includes

// 低效实现(每次调用都遍历数组)
function isHTMLTag(tag) {
  return ['div', 'span', 'img'].includes(tag);
}
  • 性能损耗:数组查找时间复杂度 O(n),大列表时性能显著下降
  • 大小写敏感:需额外处理 tag.toLowerCase() 逻辑
  • 内存冗余:每次调用都需重新创建数组

总结

makeMap 是一个高效、灵活的字符串匹配工具函数,通过预生成映射对象和闭包优化,实现了:

  1. 快速查找(O(1) 时间复杂度)
  2. 可选的大小写敏感控制
  3. 内存友好(对象复用)
  4. 防御性编程(无原型链污染)

适用于需要频繁校验字符串是否属于预定义集合的场景,尤其在框架、工具库等对性能敏感的场景中广泛使用。

本文地址:https://www.tides.cn/p_vue-source-make-map