RegExp.prototype[Symbol.replace]()

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2020 年 1 月⁩ 起,所有主流浏览器均已支持。

[Symbol.replace]() 方法是 RegExp 实例上的一种方法,它规定了当正则表达式被用作模式参数时,String.prototype.replace()String.prototype.replaceAll() 的行为。

试一试

class RegExp1 extends RegExp {
  [Symbol.replace](str) {
    return RegExp.prototype[Symbol.replace].call(this, str, "#!@?");
  }
}

console.log("football".replace(new RegExp1("foo")));
// Expected output: "#!@?tball"

语法

js
regexp[Symbol.replace](str, replacement)

参数

str

一个作为替换目标的 String

replacement

可以是字符串或函数。

  • 如果是一个字符串,它将替换当前正则表达式匹配到的子字符串。支持一些特殊的替换模式;请参阅 String.prototype.replace“将字符串指定为替换内容” 部分。
  • 如果是一个函数,它将为每一次匹配调用,并使用其返回值作为替换文本。传递给该函数的参数在 String.prototype.replace“将函数指定为替换内容” 部分进行了描述。

返回值

一个新的字符串,其中一个、一些或所有模式匹配项都被指定的替换内容替换。

描述

如果 pattern 参数是一个 RegExp 对象,则 String.prototype.replace()String.prototype.replaceAll() 会在内部调用此方法。例如,以下两个示例返回相同的结果。

js
"abc".replace(/a/, "A");

/a/[Symbol.replace]("abc", "A");

如果正则表达式是全局的(带有 g 标志),则会反复调用正则表达式的 exec() 方法,直到 exec() 返回 null。否则,exec() 只会被调用一次。对于每一次 exec() 的结果,都会根据 String.prototype.replace() 的描述来准备替换。

由于 [Symbol.replace]() 会持续调用 exec() 直到其返回 null,并且 exec() 在最后一次匹配失败时会自动将正则表达式的 lastIndex 重置为 0,因此 [Symbol.replace]() 在退出时通常不会产生副作用。然而,当正则表达式是 粘性的 但非全局的,lastIndex 不会被重置。在这种情况下,每次调用 replace() 可能会返回不同的结果。

js
const re = /a/y;

for (let i = 0; i < 5; i++) {
  console.log("aaa".replace(re, "b"), re.lastIndex);
}

// baa 1
// aba 2
// aab 3
// aaa 0
// baa 1

当正则表达式是粘性且全局的,它仍然会执行粘性匹配——即,它会尝试匹配 lastIndex 之后的所有出现项,但会失败。

js
console.log("aa-a".replace(/a/gy, "b")); // "bb-a"

如果当前匹配是一个空字符串,lastIndex 仍然会被推进——如果正则表达式是 Unicode 感知的,它将前进一个 Unicode 码点;否则,它将前进一个 UTF-16 码单元。

js
console.log("😄".replace(/(?:)/g, " ")); // " \ud83d \ude04 "
console.log("😄".replace(/(?:)/gu, " ")); // " 😄 "

此方法用于自定义 RegExp 子类中的替换行为。

示例

直接调用

此方法几乎可以与 String.prototype.replace() 以相同的方式使用,除了 this 不同以及参数顺序不同。

js
const re = /-/g;
const str = "2016-01-01";
const newStr = re[Symbol.replace](str, ".");
console.log(newStr); // 2016.01.01

在子类中使用 [Symbol.replace]()

RegExp 的子类可以覆盖 [Symbol.replace]() 方法来修改默认行为。

js
class MyRegExp extends RegExp {
  constructor(pattern, flags, count) {
    super(pattern, flags);
    this.count = count;
  }
  [Symbol.replace](str, replacement) {
    // Perform [Symbol.replace]() `count` times.
    let result = str;
    for (let i = 0; i < this.count; i++) {
      result = RegExp.prototype[Symbol.replace].call(this, result, replacement);
    }
    return result;
  }
}

const re = new MyRegExp("\\d", "", 3);
const str = "01234567";
const newStr = str.replace(re, "#"); // String.prototype.replace calls re[Symbol.replace]().
console.log(newStr); // ###34567

规范

规范
ECMAScript® 2026 语言规范
# sec-regexp.prototype-%symbol.replace%

浏览器兼容性

另见