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 吧?

资料来源


<<:  op.26 《全领域》-全域开发实战 - 居家植物盆栽 Mvt I (NodeMCU & MQTT)

>>:  DAY26 第一个完整程序练习,一台计算机!(一)

[Day 14 - 小试身手] 用HTML、CSS、JS打造个人网站 (1)

所有的网站大概可以分成两类:静态网页、动态网页,静态网页顾名思义就是静止的网页,不会去太频繁的更新内...

Day 7 - 计算属性和监听器

计算属性(Computed Property) 当我们今天想针对某一变数做运算或是处理时,可以透过模...

【LeetCode】Backtracking

Backtracking:通常是用在需要纪录路径的 DFS 时。 往前搜寻,发现目前的元素不符合条件...

[FGL] 列出树状表所有节点路径的思路与实作

在ERP体系内,除了一般表格之外,就剩下树状结构了:部门组织、产品结构、销售网路等等,都是透过标定...

Day22:【技术篇】CSS 的变数运用技巧(1)

一、前言   在 JavaScript 的世界里有变数,那初学者们也知道 CSS (阶层式样式表,C...