RegExp: lastIndex
BaselineWidely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
ThelastIndex
data property of aRegExp
instance specifies the index at which to start the next match.
Try it
const regex1 = /foo/g;const str1 = "table football, foosball";regex1.test(str1);console.log(regex1.lastIndex);// Expected output: 9regex1.test(str1);console.log(regex1.lastIndex);// Expected output: 19
Value
A non-negative integer.
Property attributes ofRegExp: lastIndex | |
---|---|
Writable | yes |
Enumerable | no |
Configurable | no |
Description
This property is set only if the regular expression instance used theg
flag to indicate a global search, or they
flag to indicate a sticky search. The following rules apply whenexec()
is called on a given input:
- If
lastIndex
is greater than the length of the input,exec()
will not find a match, andlastIndex
will be set to 0. - If
lastIndex
is equal to or less than the length of the input,exec()
will attempt to match the input starting fromlastIndex
.- If
exec()
finds a match, thenlastIndex
will be set to the position of the end of the matched string in the input. - If
exec()
does not find a match, thenlastIndex
will be set to 0.
- If
Other regex-related methods, such asRegExp.prototype.test()
,String.prototype.match()
,String.prototype.replace()
, etc., callexec()
under the hood, so they have different effects onlastIndex
. See their respective pages for details.
Examples
Using lastIndex
Consider the following sequence of statements:
const re = /(hi)?/g;
Matches the empty string.
console.log(re.exec("hi"));console.log(re.lastIndex);
Returns["hi", "hi"]
withlastIndex
equal to 2.
console.log(re.exec("hi"));console.log(re.lastIndex);
Returns["", undefined]
, an empty array whose zeroth element is the match string. In this case, the empty string becauselastIndex
was 2 (and still is 2) andhi
has length 2.
Using lastIndex with sticky regexes
ThelastIndex
property is writable. You can set it to make the regex start its next search at a given index.
They
flag almost always requires settinglastIndex
. It always matches strictly atlastIndex
and does not attempt any later positions. This is usually useful for writing parsers, when you want to match tokens only at the current position.
const stringPattern = /"[^"]*"/y;const input = `const message = "Hello world";`;stringPattern.lastIndex = 6;console.log(stringPattern.exec(input)); // nullstringPattern.lastIndex = 16;console.log(stringPattern.exec(input)); // ['"Hello world"']
Rewinding lastIndex
Theg
flag also benefits from settinglastIndex
. One common use case is when the string is modified in the middle of a global search. In this case, we may miss a particular match if the string is shortened. We can avoid this by rewindinglastIndex
.
const mdLinkPattern = /\[[^[\]]+\]\((?<link>[^()\s]+)\)/dg;function resolveMDLink(line) { let match; let modifiedLine = line; while ((match = mdLinkPattern.exec(modifiedLine))) { const originalLink = match.groups.link; const resolvedLink = originalLink.replaceAll(/^files|\/index\.md$/g, ""); modifiedLine = modifiedLine.slice(0, match.indices.groups.link[0]) + resolvedLink + modifiedLine.slice(match.indices.groups.link[1]); // Rewind the pattern to the end of the resolved link mdLinkPattern.lastIndex += resolvedLink.length - originalLink.length; } return modifiedLine;}console.log( resolveMDLink( "[`lastIndex`](files/en-us/web/javascript/reference/global_objects/regexp/lastindex/index.md)", ),); // [`lastIndex`](/en-us/web/javascript/reference/global_objects/regexp/lastindex)console.log( resolveMDLink( "[`ServiceWorker`](files/en-us/web/api/serviceworker/index.md) and [`SharedWorker`](files/en-us/web/api/sharedworker/index.md)", ),); // [`ServiceWorker`](/en-us/web/api/serviceworker) and [`SharedWorker`](/en-us/web/api/sharedworker)
Try deleting themdLinkPattern.lastIndex += resolvedLink.length - originalLink.length
line and running the second example. You will find that the second link is not replaced correctly, because thelastIndex
is already past the link's index after the string is shortened.
Warning:This example is for demonstration only. To deal with Markdown, you should probably use a parsing library instead of regex.
Optimizing searching
You can optimize searching by settinglastIndex
to a point where previous possible occurrences can be ignored. For example, instead of this:
const stringPattern = /"[^"]*"/g;const input = `const message = "Hello " + "world";`;// Pretend we've already dealt with the previous parts of the stringlet offset = 26;const remainingInput = input.slice(offset);const nextString = stringPattern.exec(remainingInput);console.log(nextString[0]); // "world"offset += nextString.index + nextString.length;
Consider this:
stringPattern.lastIndex = offset;const nextString = stringPattern.exec(remainingInput);console.log(nextString[0]); // "world"offset = stringPattern.lastIndex;
This is potentially more performant because we avoid string slicing.
Avoiding side effects
The side effects caused byexec()
can be confusing, especially if the input is different for eachexec()
.
const re = /foo/g;console.log(re.test("foo bar")); // trueconsole.log(re.test("foo baz")); // false, because lastIndex is non-zero
This is even more confusing when you are hand-modifyinglastIndex
. To contain the side effects, remember to resetlastIndex
after each input is completely processed.
const re = /foo/g;console.log(re.test("foo bar")); // truere.lastIndex = 0;console.log(re.test("foo baz")); // true
With some abstraction, you can requirelastIndex
to be set to a particular value before eachexec()
call.
function createMatcher(pattern) { // Create a copy, so that the original regex is never updated const regex = new RegExp(pattern, "g"); return (input, offset) => { regex.lastIndex = offset; return regex.exec(input); };}const matchFoo = createMatcher(/foo/);console.log(matchFoo("foo bar", 0)[0]); // "foo"console.log(matchFoo("foo baz", 0)[0]); // "foo"
Specifications
Specification |
---|
ECMAScript® 2026 Language Specification # sec-properties-of-regexp-instances |