JS: Regex lastIndex

By Xah Lee. Date: . Last updated: .

What is .lastIndex

.lastIndex

A index for the target string, used by some regex functions.

this property is set automatically by regex functions, and only if the regex object has Regex Flag g (global) or Regex Flag y (sticky).

in the case of RegExp.prototype.exec and RegExp.prototype.test, the behavior is:

If a match is found, lastIndex is set to the end position of the matched substring. If no match is found, lastIndex is set to 0.

lastIndex can be set. e.g. myRegexObj.lastIndex = 5.

Each regex object has own lastIndex

const rgx = /x/;
console.log(rgx.lastIndex);
// 0

console.log(Object.hasOwn(rgx, "lastIndex"));
// true

Example. demo with regex.test method

// without regex flag g or flag y , lastIndex is always 0.
// test with RegExp.prototype.test

const xtext = "012-45-78-";
const rgx = /-/;
console.assert(rgx.lastIndex === 0);

console.assert(rgx.test(xtext) === true);
console.assert(rgx.lastIndex === 0);

console.assert(rgx.test(xtext) === true);
console.assert(rgx.lastIndex === 0);
// with regex flag g, lastIndex is advanced or set to 0.
// test with RegExp.prototype.test

const xtext = "012-45-78-";
const rgx = /-/g;
console.assert(rgx.lastIndex === 0);

console.assert(rgx.test(xtext) === true);
console.assert(rgx.lastIndex === 4);

console.assert(rgx.test(xtext) === true);
console.assert(rgx.lastIndex === 7);
// with regex flag y, lastIndex is advanced or set to 0.
// test with RegExp.prototype.test

const xtext = "012-45-78-";
const rgx = /-/y;

rgx.lastIndex = 3;
console.log(rgx.lastIndex);
// 3

console.log(rgx.test(xtext));
// true

console.log(rgx.lastIndex);
// 4

console.log(rgx.test(xtext));
// false

console.log(rgx.lastIndex);
// 0

Example. demo with regex.exec method

// without regex flag g or flag y , lastIndex is always 0.
const xtext = "012-45-78-";
const rgx = /-/;

console.assert(rgx.lastIndex === 0);

console.log(rgx.exec(xtext));
// [ "-", index: 3, input: "012-45-78-", groups: undefined ]

console.assert(rgx.lastIndex === 0);

console.log(rgx.exec(xtext));
// [ "-", index: 3, input: "012-45-78-", groups: undefined ]

console.assert(rgx.lastIndex === 0);
// with regex flag g. lastIndex is advanced or set to 0.
// test with RegExp.prototype.exec

const xtext = "012-45-78-";
const rgx = /-/g;
console.assert(rgx.lastIndex === 0);

console.log(rgx.exec(xtext));
// [ "-", index: 3, input: "012-45-78-", groups: undefined ]

console.assert(rgx.lastIndex === 4);

console.log(rgx.exec(xtext));
// [ "-", index: 6, input: "012-45-78-", groups: undefined ]

console.assert(rgx.lastIndex === 7);

console.log(rgx.exec(xtext));
// [ "-", index: 9, input: "012-45-78-", groups: undefined ]

console.assert(rgx.lastIndex === 10);

console.log(rgx.exec(xtext));
// null

console.assert(rgx.lastIndex === 0);

Regex functions that use lastIndex

which js regex methods use lastIndex

(ai answer)

Main ones: RegExp.prototype.exec() and RegExp.prototype.test().

These (and methods that call them) only use/update lastIndex when the regex has the g (global) or y (sticky) flag. Otherwise lastIndex is ignored.

Behavior summary

Method Uses / updates lastIndex? Notes
regex.exec(str) Yes Primary method. Advances on match, resets to 0 on failure.
regex.test(str) Yes Calls exec() under the hood. Same side effects.
str.match(regex) Yes (if g) Repeatedly calls exec. Usually ends with lastIndex = 0.
str.replace(regex, …) / replaceAll Yes (if g or y) Sets to 0 at start for global. Sticky (y only) can leave it changed.
str.matchAll(regex) On a copy Creates a new regex (via Symbol.species) that copies lastIndex. Original is unchanged.
str.search(regex) Temporarily Sets to 0, runs, then restores previous value. No lasting side effect.
str.split(regex) On a copy Original lastIndex is not modified.

Key takeaway: Reusing a global/sticky regex across calls (especially test/exec) is a common source of bugs because lastIndex persists. Reset it (regex.lastIndex = 0) or create a fresh regex when needed.