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
是一个高效、灵活的字符串匹配工具函数,通过预生成映射对象和闭包优化,实现了:
- 快速查找(O(1) 时间复杂度)
- 可选的大小写敏感控制
- 内存友好(对象复用)
- 防御性编程(无原型链污染)
适用于需要频繁校验字符串是否属于预定义集合的场景,尤其在框架、工具库等对性能敏感的场景中广泛使用。
本文地址:https://www.tides.cn/p_vue-source-make-map