(new Reg("A","g")).test(str) 连续两次的结果,第二次不是期望值

69 阅读1分钟

bug背景

const reg  = /CAM/gi
reg.test("FCAM_B0") // true
reg.test("FCAM_A0") // false

在 JavaScript 中,使用带有 g(全局)标志的正则表达式进行多次 test() 调用时会出现一个特殊行为,这可能会导致你观察到的现象。

问题分析

const reg = /CAM/gi;
reg.test("FCAM_B0");  // 返回 true
reg.test("FCAM_A0");  // 返回 false(但你可能期望 true)

原因解释

  1. 当你使用 g 标志时,正则表达式对象会维护一个 lastIndex 属性,记录上次匹配的位置
  2. 第一次调用 test("FCAM_B0")
    • 在 "FCAM_B0" 中找到 "CAM"(位置 1)
    • 设置 lastIndex = 4(匹配结束的位置)
  3. 第二次调用 test("FCAM_A0")
    • lastIndex = 4 开始搜索
    • "FCAM_A0" 只有 7 个字符,从位置 4 开始找不到 "CAM"
    • 返回 false 并重置 lastIndex = 0

解决方案

方法1:不使用全局标志(推荐)

const reg = /CAM/i;  // 去掉 g 标志
reg.test("FCAM_B0");  // true
reg.test("FCAM_A0");  // true

方法2:每次测试前重置 lastIndex

const reg = /CAM/gi;
reg.test("FCAM_B0");  // true
reg.lastIndex = 0;    // 重置搜索位置
reg.test("FCAM_A0");  // true

方法3:每次创建新的正则表达式

/CAM/gi.test("FCAM_B0");  // true
/CAM/gi.test("FCAM_A0");  // true

何时需要使用 g 标志

g 标志主要用于需要多次匹配的场景,如:

  • String.prototype.match()
  • String.prototype.replace()
  • 循环中的多次匹配

对于简单的 test() 检查,通常不需要 g 标志。