試一試
const regex = /foo/g;
const str = "table football, foosball";
regex.test(str);
console.log(regex.lastIndex);
// Expected output: 9
regex.test(str);
console.log(regex.lastIndex);
// Expected output: 19
值
一個非負整數。
RegExp: lastIndex 的屬性特性 | |
|---|---|
| 可寫 | 是 |
| 可列舉 | 否 |
| 可配置 | 否 |
描述
僅當正則表示式例項使用了 g 標誌(表示全域性搜尋)或 y 標誌(表示粘性搜尋)時,此屬性才會被設定。當在給定輸入上呼叫 exec() 時,適用以下規則:
- 如果
lastIndex大於輸入的長度,exec()將不會找到匹配項,並且lastIndex會被設定為 0。 - 如果
lastIndex等於或小於輸入的長度,exec()將會嘗試從lastIndex開始匹配輸入。- 如果
exec()找到匹配項,則lastIndex將會被設定為匹配字串在輸入中的結束位置。 - 如果
exec()沒有找到匹配項,則lastIndex將會被設定為 0。
- 如果
其他與正則表示式相關的函式,例如 RegExp.prototype.test()、String.prototype.match()、String.prototype.replace() 等,在底層都會呼叫 exec(),因此它們對 lastIndex 有不同的影響。有關詳細資訊,請參閱它們各自的頁面。
示例
使用 lastIndex
考慮以下語句序列:
const re = /(hi)?/g;
匹配空字串。
console.log(re.exec("hi"));
console.log(re.lastIndex);
返回 ["hi", "hi"],此時 lastIndex 等於 2。
console.log(re.exec("hi"));
console.log(re.lastIndex);
返回 ["", undefined],一個空陣列,其第零個元素是匹配的字串。在這種情況下,空字串是因為 lastIndex 是 2(並且仍然是 2),而 hi 的長度是 2。
將 lastIndex 與粘性正則表示式一起使用
lastIndex 屬性是可寫的。你可以設定它來讓正則表示式從指定的索引開始下一次搜尋。
y 標誌幾乎總是需要設定 lastIndex。它總是嚴格地在 lastIndex 處匹配,並且不會嘗試後面的位置。這對於編寫解析器非常有用,當你只想在當前位置匹配標記時。
const stringPattern = /"[^"]*"/y;
const input = `const message = "Hello world";`;
stringPattern.lastIndex = 6;
console.log(stringPattern.exec(input)); // null
stringPattern.lastIndex = 16;
console.log(stringPattern.exec(input)); // ['"Hello world"']
重置 lastIndex
g 標誌也受益於設定 lastIndex。一個常見的用例是當字串在全域性搜尋過程中被修改時。在這種情況下,如果字串變短,我們可能會錯過特定的匹配。我們可以透過重置 lastIndex 來避免這種情況。
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)
嘗試刪除 mdLinkPattern.lastIndex += resolvedLink.length - originalLink.length 這一行並執行第二個示例。你會發現第二個連結沒有被正確替換,因為在字串變短後,lastIndex 已經超過了連結的索引。
警告: 此示例僅用於演示。要處理 Markdown,你可能應該使用解析庫而不是正則表示式。
最佳化搜尋
你可以透過將 lastIndex 設定到一個可以忽略先前可能出現的匹配的位置來最佳化搜尋。例如,而不是這樣做:
const stringPattern = /"[^"]*"/g;
const input = `const message = "Hello " + "world";`;
// Pretend we've already dealt with the previous parts of the string
let offset = 26;
const remainingInput = input.slice(offset);
const nextString = stringPattern.exec(remainingInput);
console.log(nextString[0]); // "world"
offset += nextString.index + nextString.length;
考慮這個:
stringPattern.lastIndex = offset;
const nextString = stringPattern.exec(remainingInput);
console.log(nextString[0]); // "world"
offset = stringPattern.lastIndex;
這可能更具效能優勢,因為我們避免了字串切片。
避免副作用
exec() 引起的副作用可能令人困惑,特別是當每次 exec() 的輸入都不同時。
const re = /foo/g;
console.log(re.test("foo bar")); // true
console.log(re.test("foo baz")); // false, because lastIndex is non-zero
當你手動修改 lastIndex 時,這會更加令人困惑。為了控制副作用,請記住在處理完每個輸入後重置 lastIndex。
const re = /foo/g;
console.log(re.test("foo bar")); // true
re.lastIndex = 0;
console.log(re.test("foo baz")); // true
透過一些抽象,你可以要求在每次 exec() 呼叫之前將 lastIndex 設定為特定值。
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"
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-properties-of-regexp-instances |
瀏覽器相容性
載入中…