本篇介紹 ES2021 (ES12) 提供的 String.prototype.replaceAll()
。
將一個字串中的指定子字串,取代成另一個字串,是很常見的字串處理情境。
例如:要將 URL 的 query 字串 q=query+string+parameters
中的 +
字元替換成空白字元:
// 原字串
'q=query+string+parameters'
// 替換成
'q=query string parameters'
常見有以下作法:
String.prototype.replace()
String.prototype.split()
+ Array.prototype.join()
下面分別說明這兩種作法的小問題。
String.prototype.replace()
若要一次替換多個子字串,String.prototype.replace()
的第一個參數只能使用設定 global
flag 的 RegExp,而不是用字串。因為字串只能替換第一個子字串,不能一次替換多個子字串。
let query = 'q=query+string+parameters';
let queryWithSpaces = query.replace(/\+/g, ' ');
console.log(queryWithSpaces);
// q=query string parameters
這種方法的缺點是要用 RegExp,並且是轉義過的字元,像此範例用的是轉義過的 +
字元 (因為在 RegExp 的 pattern 中,+
有特殊的意義,代表 match 一個以上)。
String.prototype.split()
+ Array.prototype.join()
另一種常見的作法是同時使用 String.prototype.split()
和 Array.prototype.join()
let query = 'q=query+string+parameters';
let queryWithSpaces = query.split('+').join(' ');
console.log(queryWithSpaces);
// q=query string parameters
這種方法雖然可以不用處理跳脫字元 (escaping),但需要先將字串拆成包含多個字串的陣列,然後再將這些字串拼起來。
所以可以看到以上這些方法的小問題,就是不夠直覺。原本只是想將所有的 +
字元,全部改為空白的簡單需求,但因為 JavaScript 過去的限制,只能用一些獨特的小技巧才能處理 QQ。
那有沒有更直覺的作法?這就是本篇要介紹的 String.prototype.replaceAll()
派上用場的時刻!
String.prototype.replaceAll()
把前面的範例換成 String.prototype.replaceAll()
:
let query = 'q=query+string+parameters';
let queryWithSpaces = query.replaceAll('+', ' ');
console.log(queryWithSpaces);
// q=query string parameters
就這樣!很簡單吧!完全不用說明你就會了 XD
String.prototype.replace()
vs. String.prototype.replaceAll()
兩者的 signature 一樣 (即參數名稱、參數數量一樣):
String.prototype.replace(searchValue, replaceValue)
String.prototype.replaceAll(searchValue, replaceValue)
但兩者的行為有些不同:
searchValue
是字串時:
replace()
只會替換第一個 searchValue
replaceAll()
會替換所有 searchValue
searchValue
不是設定 global
flag 的 RegExp 時:
replace()
只會替換第一個 searchValue
replaceAll()
會拋出 TypeError
exception,因為要避免與 replaceAll()
的行為不符合 (即不是全部替換)let query = 'q=query+string+parameters';
query.replaceAll(/\+/, ' ');
// TypeError: String.prototype.replaceAll called with a non-global RegExp argument
若 searchValue
是設定 global
flag 的 RegExp 時,兩著的行為一樣:
let query = 'q=query+string+parameters';
let queryWithSpaces1 = query.replace(/\+/g, ' ');
console.log(queryWithSpaces1);
// q=query string parameters
let queryWithSpaces2 = query.replaceAll(/\+/g, ' ');
console.log(queryWithSpaces2);
// q=query string parameters
雖然兩者的行為一致,但應該很少會在
replaceAll
使用 RegExp 吧?
String.prototype.replaceAll
| 2ality