string.prototype.replace()支持函数回调实现上下文感知的动态脱敏,参数含匹配串、捕获组、位置及原字符串;可精准处理手机号、邮箱等场景,并通过闭包封装配置确保纯函数性。

可以通过 String.prototype.replace() 的函数回调,在匹配到敏感内容时动态生成脱敏结果,实现灵活、上下文感知的文本处理。
理解回调函数的参数含义
当 replace() 的第二个参数是函数时,该函数会接收多个参数:
- 匹配的完整字符串(match):正则匹配到的整个子串
-
捕获组内容(group1, group2, ...):按顺序传入每个
()捕获的内容 - 匹配起始位置(offset):该次匹配在原字符串中的索引
- 原始字符串(string):被替换的源文本
这些参数让回调能根据上下文决定如何脱敏,比如保留首尾字符、按长度差异化处理、或结合前后文判断是否真为敏感信息。
实现手机号动态脱敏(保留号段+掩码)
常见需求是保留前3位和后4位,中间用 * 替换。利用捕获组可精准控制:
const text = "联系我:13812345678 或 15987654321";
const masked = text.replace(/(1[3-9]\d)(\d{4})(\d{4})/g, (match, prefix, mid, suffix) => {
return `${prefix}****${suffix}`;
});
// → "联系我:138****5678 或 159****4321"
这里正则分三组捕获,回调中直接拼接,避免硬编码索引,逻辑清晰且易维护。
根据匹配长度或位置做条件脱敏
某些场景需差异化处理:短号码不脱敏、长文本中的邮箱只脱敏用户名部分、或仅替换独立单词(非子串)。例如:
const content = "邮箱 test@example.com 和 admin@test.org 都要处理";
<p>content.replace(/\b([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+.[a-zA-Z]{2,})\b/g, (match, user, domain) => {
const maskedUser = user.length > 2 ? user[0] + '*'.repeat(user.length - 2) + user.slice(-1) : '<strong>';
return <code>${maskedUser}@${domain}</code>;
});
// → "邮箱 t</strong>t@example.com 和 a**n@test.org 都要处理"
</p>
回调内可自由写判断逻辑,比如对 user 长度做分支,或检查 offset 是否在代码块内(配合外围解析),实现“智能”脱敏。
避免全局副作用,保持纯函数行为
回调函数应是纯的:不修改外部变量、不依赖可变状态、相同输入始终返回相同输出。若需计数(如“第N个身份证号”)、或依赖外部配置,建议用闭包封装:
const createIdCardReplacer = (maskChar = '*') => {
return (match, num, year, rest) => {
// 只掩码出生年份后的8位(非全部)
const maskedRest = rest.slice(0, 4) + maskChar.repeat(4);
return `${num}${year}${maskedRest}`;
};
};
<p>const idReplacer = createIdCardReplacer('•');
"张三身份证:11010119900307235X".replace(/(\d{6})(\d{4})(\d{8})(\w)/g, idReplacer);
// → "张三身份证:11010119900307••••X"
</p>
闭包让配置复用、逻辑隔离,也方便单元测试和多实例共存(如不同规则处理不同字段)。










