本文深入解析 JavaScript 中 String 类的 replace 方法。当 replacement 参数为函数时,详细说明了回调函数的参数构成:第一个为完整匹配串,中间为子表达式匹配结果,倒数第二个为索引,最后为原字符串。通过无子表达式和有子表达式的两个代码示例,验证了参数数量与正则捕获组的对应关系。
JavaScript String replace 函数回调参数详解
关于回调函数参数的说明十分准确:
首个参数接收匹配到的子串,最后一个参数为原始字符串,而倒数第二个参数则记录了该匹配子串在原字符串中的起始索引位置。
然而,第二参数至倒数第三参数之间的内容究竟代表什么?W3school 文档中已提供了明确解答:
相关代码实现如下:
replace() 方法的核心功能是在字符串中用指定字符替换现有字符,或替换与正则表达式匹配的子串。其标准语法格式为:
stringObject.replace(regexp/substr,replacement)
其中的 replacement 参数既可以是普通字符串,也可以是函数。若指定为字符串,则所有匹配项均直接由该字符串替换。
根据 ECMAScript v3 规范,replace() 方法的 replacement 参数支持函数形式。此时,每一次匹配都会触发该函数的执行。
函数执行后返回的字符串将作为最终的替换内容。该回调函数的第一个参数即为匹配模式的完整字符串。
字符串,可以有 0 个或多个这样的参数。接下来的参数是一个整数,声明了匹配在 stringObject 中出现的位置。最后一个参数
紧接着是一个整数,表示匹配内容在原 stringObject 中的起始位置。最后一个参数则是原始的 stringObject 对象本身。 由此可见,replacement 函数中从第二个到倒数第三个参数,专门用于接收“与模式中子表达式匹配的字符串”,其具体数量取决于正则表达式中子表达式的定义个数。
基于上述原理,下面通过两个对比示例进行具体说明:
示例一:
待处理字符串为:"CJ9080"
使用的匹配模式为:/CJ[0-9]{2}/g(未定义子表达式)
预期运行结果:
此时 replacement 函数共接收 3 个参数,具体分别为:
【0】匹配到的完整字符串“CJ90”
【1】匹配起始索引 0
【2】原始字符串“CJ9080”
对应的测试代码如下:
代码实现如下:
function replaceStr(s) {
return s.replace(/CJ[0-9]{2}/g,
function(){
for (var i = 0, len = arguments.length; i < len; i++) {
console.info("Argument " + i + ": " + arguments[i]);
}
});
}; 实际运行结果:

示例二:
待处理字符串为:"CJ9080"
使用的匹配模式为:/((CJ)([0-9]{2}))/g(包含 3 个子表达式:(CJ[0-9]{2}), (CJ), ([0-9]{2}))
预期运行结果:
此时 replacement 函数共接收 6 个参数,具体分别为:
【0】完整匹配字符串 "CJ90"
【1】第一个子表达式匹配结果 "CJ90"
【2】第二个子表达式匹配结果 "CJ"
【3】第三个子表达式匹配结果 "90"
【4】匹配起始索引 0
【5】原始字符串 "CJ9080"
对应的测试代码如下:
代码实现如下:
function replaceStr(s) {
return s.replace(/((CJ)([0-9]{2}))/g,
function(){
for (var i = 0, len = arguments.length; i < len; i++) {
console.info("Argument " + i + ": " + arguments[i]);
}
});
}; 实际运行结果:

对比两个测试例子的结果,均与预期完全一致。这证实了当 replace 方法的 replacement 参数为函数时,其参数结构确实符合 W3school 的描述:
【0】:正则匹配模式的完整字符串;
【1 至 (length - 3)】:与模式中子表达式匹配的字符串,数量取决于子表达式个数,0 个或多个;
【length - 2】:匹配串在原字符串中的起始索引位置,从 0 开始计数;
【length - 1】:原始字符串对象。