Run the same test three times
This small example uses one persistent RegExp instance and the same input each time. The first match advances lastIndex to 1. The second search begins there and fails because no further a exists; that failure resets the cursor. The third test starts at zero again.
Run this snippet in a JavaScript console to reproduce object reuse. Regex Tester is useful for exploring patterns and captures, but an isolated tester run does not reproduce every lifecycle choice in your application.
const re = /a/g;
console.log(re.test("a"), re.lastIndex); // true 1
console.log(re.test("a"), re.lastIndex); // false 0
console.log(re.test("a"), re.lastIndex); // true 1Choose a pattern lifetime that fits the operation
For a yes/no whole-string validation, a non-global expression is usually simpler. Anchors define the extent of the match, while the absence of g avoids the persistent cursor. Anchors by themselves do not neutralize the global flag.
For iterating through matches, state is intentional. A loop using exec needs the global flag and must handle zero-length matches safely, or use a suitable matchAll workflow. Sticky y differs from g because it requires a match exactly at lastIndex rather than searching ahead.
Resetting lastIndex can make an existing shared expression behave predictably for one operation, but shared mutable state is easy to misuse across helper calls. A fresh RegExp per independent task is often easier to reason about.
| Task | Example | State consideration |
|---|---|---|
| Simple validation | /^[A-Z]+$/.test(value) | No global cursor |
| Independent global scan | new RegExp(pattern, "g") | Fresh cursor per scan |
| Reuse an instance intentionally | re.lastIndex = 0 before use | Caller owns the reset |
| Sticky token scanning | /token/y | Must match exactly at the cursor |
Add a regression case with repeated calls
When a validation helper fails intermittently, call it twice with the same known-good input and once with invalid input. Then test two distinct strings in succession. If the result changes with call order, inspect captured or cached RegExp objects.
Separate this problem from catastrophic backtracking: a stateful regex can be fast but surprising, while a fresh regex can still be expensive on adversarial input. Review both correctness and execution limits when accepting user-defined patterns.
const isUppercase = value => /^[A-Z]+$/.test(value);
console.assert(isUppercase("ABC"));
console.assert(isUppercase("ABC"));
console.assert(!isUppercase("AbC"));References
Use the linked specifications and product documentation to check behavior in your own environment.
Continue troubleshooting
Related tools
Frequently asked questions
Does test always start at zero?
No. Global and sticky expressions use their current lastIndex value.
Do anchors fix global regex state?
No. Anchors constrain matching positions but do not remove the persistent cursor.
Does a fresh regex prevent slow matching?
No. Pattern complexity and input still determine the work performed by the engine.