iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
1
Modern Web

JavaScript 之旅系列 第 26

JavaScript 之旅 (26):String.prototype.replaceAll()

本篇介紹 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 吧?

資料來源


上一篇
JavaScript 之旅 (25):Nullish Coalescing Operator ( ?? 運算子)
下一篇
JavaScript 之旅 (27):Promise.any() & AggregateError
系列文
JavaScript 之旅30

尚未有邦友留言

立即登入留言