perf: replace 函数 replacer 回调免每匹配整串复制

回调第 4 参(原字符串)由每匹配复制整串改为调用方预构一次:
原始字符串 receiver 直接复用原值零拷贝,对象 receiver 提升为单次会话串。
覆盖 String.prototype.replace/replaceAll 与 RegExp.prototype[Symbol.replace]
的函数 replacer 路径。补回调第 4 参断言测试与 fn-replacer 压测。
This commit is contained in:
2026-08-14 21:00:43 +08:00
parent d419272321
commit f7866585d1
4 changed files with 61 additions and 11 deletions
@@ -333,6 +333,28 @@ fn string_replace_function_replacer_string_pattern() {
assert_eq!(to_str(&vm, s), "a1c");
}
#[test]
fn string_replace_function_replacer_string_arg() {
// 回调第 4 参为原字符串:原始 receiver 直接传值(=== 原串),
// 对象 receiver 传 ToString 内容;字符串/正则 pattern、replace/replaceAll 全覆盖。
let mut vm = Vm::new();
let s = eval(&mut vm, "'abc'.replace('b', function(m, o, str){ return str })").unwrap();
assert_eq!(to_str(&vm, s), "aabcc");
let s = eval(&mut vm, "'abc'.replace(/b/, function(m, o, str){ return str })").unwrap();
assert_eq!(to_str(&vm, s), "aabcc");
let s = eval(&mut vm, "'abc'.replaceAll('b', function(m, o, str){ return str })").unwrap();
assert_eq!(to_str(&vm, s), "aabcc");
// 第 4 参与原始字符串按内容恒等(=== 对字符串按值比较)。
let s = eval(&mut vm, "var str='abc'; str.replace('b', function(m, o, str2){ return str2 === str })").unwrap();
assert_eq!(to_str(&vm, s), "atruec");
// boxed receiver 走对象 ToString 路径,第 4 参为解箱后内容。
let s = eval(&mut vm, "new String('abc').replace('b', function(m, o, str){ return str })").unwrap();
assert_eq!(to_str(&vm, s), "aabcc");
// RegExp.prototype[Symbol.replace] 直调路径(非 String.prototype.replace 快路径)。
let s = eval(&mut vm, "/b/[Symbol.replace]('abc', function(m, o, str){ return str })").unwrap();
assert_eq!(to_str(&vm, s), "aabcc");
}
#[test]
fn string_replace_missing_replacement_is_undefined_string() {
// 缺失 replaceValue 按 ToString(undefined)="undefined" 替换(非空串)。