如果您曾經處理過 JavaScript 中的字串,您很有可能會遇到 String#replace
方法。String.prototype.replace(searchValue, replacement)
會傳回一個字串,其中某些符合條件的字串會根據您指定的參數進行替換
'abc'.replace('b', '_');
// → 'a_c'
'🍏🍋🍊🍓'.replace('🍏', '🥭');
// → '🥭🍋🍊🍓'
一個常見的用例是替換給定子字串的所有實例。但是,String#replace
並未直接處理此用例。當 searchValue
為字串時,只會替換子字串的第一個出現位置
'aabbcc'.replace('b', '_');
// → 'aa_bcc'
'🍏🍏🍋🍋🍊🍊🍓🍓'.replace('🍏', '🥭');
// → '🥭🍏🍋🍋🍊🍊🍓🍓'
為了解決這個問題,開發人員通常會將搜尋字串轉換成帶有全域 (g
) 旗標的正規表示法。這樣一來,String#replace
就能替換所有符合條件的字串
'aabbcc'.replace(/b/g, '_');
// → 'aa__cc'
'🍏🍏🍋🍋🍊🍊🍓🍓'.replace(/🍏/g, '🥭');
// → '🥭🥭🍋🍋🍊🍊🍓🍓'
對於開發人員來說,如果您真正想要的只是一個全域子字串替換,卻必須進行這種字串轉正規表示法的轉換,是一件很惱人的事。更重要的是,這種轉換容易出錯,而且是常見的錯誤來源!請考慮以下範例
const queryString = 'q=query+string+parameters';
queryString.replace('+', ' ');
// → 'q=query string+parameters' ❌
// Only the first occurrence gets replaced.
queryString.replace(/+/, ' ');
// → SyntaxError: invalid regular expression ❌
// As it turns out, `+` is a special character within regexp patterns.
queryString.replace(/\+/, ' ');
// → 'q=query string+parameters' ❌
// Escaping special regexp characters makes the regexp valid, but
// this still only replaces the first occurrence of `+` in the string.
queryString.replace(/\+/g, ' ');
// → 'q=query string parameters' ✅
// Escaping special regexp characters AND using the `g` flag makes it work.
將字串文字(例如 '+'
)轉換成全域正規表示法不只是移除 '
引號、用 /
斜線將其包起來,然後加上 g
旗標而已 — 我們必須對正規表示法中具有特殊意義的任何字元進行跳脫。這很容易忘記,而且很難做對,因為 JavaScript 沒有提供內建機制來跳脫正規表示法模式。
另一個解決方法是將 String#split
與 Array#join
結合使用
const queryString = 'q=query+string+parameters';
queryString.split('+').join(' ');
// → 'q=query string parameters'
這種方法可以避免任何跳脫,但會產生將字串分割成陣列部分的開銷,而且最後還要再將其黏合在一起。
顯然,這些解決方法都不是理想的。如果 JavaScript 中的基本作業(例如全域子字串替換)可以更直接了當,那不是很好嗎?
String.prototype.replaceAll
#
新的 String#replaceAll
方法解決了這些問題,並提供了一個直接的機制來執行全域子字串替換
'aabbcc'.replaceAll('b', '_');
// → 'aa__cc'
'🍏🍏🍋🍋🍊🍊🍓🍓'.replaceAll('🍏', '🥭');
// → '🥭🥭🍋🍋🍊🍊🍓🍓'
const queryString = 'q=query+string+parameters';
queryString.replaceAll('+', ' ');
// → 'q=query string parameters'
為了與語言中現有的 API 保持一致,String.prototype.replaceAll(searchValue, replacement)
的行為與 String.prototype.replace(searchValue, replacement)
完全相同,但有以下兩個例外:
- 如果
searchValue
是字串,則String#replace
只會替換子字串的第一個出現位置,而String#replaceAll
則會替換所有出現位置。 - 如果
searchValue
是非全域的 RegExp,則String#replace
只會替換單一符合條件的字串,類似於它對待字串的方式。另一方面,String#replaceAll
在這種情況下會擲回例外,因為這很可能是個錯誤:如果您真的想要「替換所有」符合條件的字串,您應該使用全域正規表示法;如果您只想替換單一符合條件的字串,可以使用String#replace
。
新功能的重要部分在於第一個項目。String.prototype.replaceAll
豐富了 JavaScript,提供了對全域子字串替換的一流支援,無需正規表示式或其他解決方法。
關於特殊替換模式的說明 #
值得注意的是:replace
和 replaceAll
都支援 特殊替換模式。雖然這些模式與正規表示式搭配使用時最有用,但其中一些模式($$
、$&
、$`
和 $'
)在執行簡單字串替換時也會生效,這可能會令人驚訝
'xyz'.replaceAll('y', '$$');
// → 'x$z' (not 'x$$z')
如果您的替換字串包含這些模式之一,而且您想按原樣使用它們,您可以選擇退出神奇替換行為,改用回傳字串的替換函式
'xyz'.replaceAll('y', () => '$$');
// → 'x$$z'
String.prototype.replaceAll
支援 #
- Chrome: 自版本 85 起支援
- Firefox: 自版本 77 起支援
- Safari: 自版本 13.1 起支援
- Node.js: 自版本 16 起支援
- Babel: 支援