RegExp: lastIndex
Baseline Widely 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.
In this article
Try it
const regex = /foo/g;const str = "table football, foosball";regex.test(str);console.log(regex.lastIndex);// Expected output: 9regex.test(str);console.log(regex.lastIndex);// Expected output: 19Value
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
lastIndexis greater than the length of the input,exec()will not find a match, andlastIndexwill be set to 0. - If
lastIndexis equal to or less than the length of the input,exec()will attempt to match the input starting fromlastIndex.- If
exec()finds a match, thenlastIndexwill be set to the position of the end of the matched string in the input. - If
exec()does not find a match, thenlastIndexwill 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-zeroThis 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")); // trueWith 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> |