让开发人员更高效的 JavaScript 字符串方法

JavaScript 最初是作为一种简单的客户端脚本语言推出的,但现在,它已成为一种真正的 WORA(Write Once Run Anywhere)语言,可让开发人员构建桌面、移动、电视、CLI 和嵌入式应用程序。JavaScript 易于初学者使用的语法、富有成效的语言特性以及管理完善的 ECMAScript 规范促使大家将 JavaScript 用于通用编程。

ECMAScript 标准提供了许多语言特性,有助于提高开发人员的工作效率。它通过内置的 String 对象引入了多种字符串方法,使开发人员能够高效地处理字符串数据。这些高效的字符串方法促使开发人员使用 JavaScript 解决文本处理问题,而无需使用外部库或从头开始编写冗长的代码。

在本教程中,我将讲解 JavaScript 中必须掌握的字符串处理方法,这些方法可以让你编写出简洁、不言自明的代码。

使用 at() 方法负索引截取字符串

JavaScript 在字符串和数组对象中实现了传统的基于括号的索引元素访问,但由于语言设计的限制,它没有像 Python 那样实现负索引支持。例如,下面代码片段中的第二条日志语句返回未定义,因为它试图查找对象属性而不是索引元素:

let m  = 'JavaScript';
console.log(m[m.length - 1]);      // t
console.log(m[-1]);                // undefined

你确实可以使用 JavaScript Proxy object 来实现字符串的负索引支持,但这并不像字符串和数组对象中内置的 at() 方法那样有效。at()方法可以简化最后一个字符的访问,具体如下:

使用 includes()、startsWith() 和 endsWith() 字符串查询方法

过去,开发人员经常使用 indexOf() 方法来搜索字符串对象中的字符串段。他们使用 Regex 或基于 indexOf()/substring()的解决方案来检查特定字符串的起点和终点。ES6 版本针对这些要求引入了单独的内置字符串方法。

includes() 方法检查字符串中是否存在特定字符集:

let m  = 'JavaScript';
console.log(m.includes('Java'));      // true

startsWith() 方法会检查字符串的起始位置,如下面的代码片段所示:

let filename  = '_testmatrix.json';
console.log(filename.startsWith('_'));      // true

与此同时,endsWith() 方法会检查字符串的结尾,如下所示:

let filename  = '_testmatrix.json';
console.log(filename.endsWith('.json'));    // true

通过这些内置字符串方法,我们可以编写简单的语句来满足一般的字符串查询要求,而无需使用基于 Regex 或其他算法的解决方案。

使用 repeat() 方法重复字符串

在通用编程语言中构造字符串时,我们经常需要重复字符串。假设您需要在终端上使用 ASCII 字符创建一条水平线。Python 允许开发者使用 * 操作符有效地处理这种情况,下面的代码片段演示了这一点:

print('+-' * 10)   # +-+-+-+-+-+-+-+-+-+-

在 ES6 之前,JavaScript 开发人员必须使用多种技巧才能在不使用循环结构的情况下重复一个字符串。大多数开发人员使用以下方法:

console.log(new Array(11).join('+-'));  // +-+-+-+-+-+-+-+-+-+-

ES6 引入了 repeat() 字符串方法,以富有成效的方式进行字符串重复,取代了旧的非自明性代码:

console.log('+-'.repeat(10));

使用字符串 trim 方法删除多余的空白字符

在各种开发场景中,我们经常需要通过删除空白字符对字符串进行预处理。例如,您可能需要删除使用<textarea> HTML 元素捕获的用户输入中的空白。过去,大多数开发人员使用 Regex 来清除字符串,具体方法如下:

function trim(str) {
  return str.replace(/^\s+|\s+$/g, '');
}

console.log(trim('  Hello JavaScript    '));   // 'Hello JavaScript'

上述 trim() 函数删除了前导和尾部空白字符。

JavaScript 在字符串对象上实现了 trim()trimStart()trimEnd() 方法,用于处理空白删除。trim()方法可以删除前导和尾部空白字符。与此同时,其他两个方法可以帮助我们有选择性地清除前导和尾部空白,下面的代码片段对此进行了演示:

let txt = '  Hello JavaScript \n ';

console.log(txt.trimStart());   // 'Hello JavaScript \n '
console.log(txt.trimEnd());     // '  Hello JavaScript'
console.log(txt.trim());        // 'Hello JavaScript'
function secret(strings, ...exps) { 
  return strings.reduce((acc, str, i) => 
    (acc + str + (exps.length > i ? '*'.repeat(exps[i].toString().length) : '')), '');
}

let txt = secret`My username is ${'Bingo'}, and my password is ${1234}`;

console.log(txt);  // My username is *****, and my password is *

上述 secret() 标记函数为模板字符串表达式中构建的所有值加上星号字符。正如你已经注意到的,我们可以通过在特定模板字符串前使用标签函数来执行该函数,而无需使用传统的基于括号的函数调用语法。

通过内置的 String.raw() 标记函数,可以存储不处理转义字符的原始字符串。假设需要用 JavaScript 存储以下 Windows 文件路径:

C:\Projects\MyProject1\myproject.config.json

我们无法在 JavaScript 中正确存储这个字符串,因为它的转义字符会被处理并删除多个字符:

let path = 'C:\Projects\MyProject1\myproject.config.json';
console.log(path); // C:ProjectsMyProject1myproject.config.json

在这里,我们可以使用 String.raw() 标签函数来防止转义字符处理:

let path = String.raw`C:\Projects\MyProject1\myproject.config.json`;
console.log(path); // C:\Projects\MyProject1\myproject.config.json

String.raw 标签函数会自动为转义字符添加双反斜线,以正确存储原始字符串。该标签函数还有助于在字符串中存储包含反斜线的 Regex 定义:

let regex = String.raw`\s*${10}\s*`;
console.log('2   10  20'.replace(new RegExp(regex), ''));   // 220

在上例中,我们将动态构建的 Regex 定义存储在字符串中,没有使用双反斜线。

使用 padStart() 和 padEnd() 方法填充字符串

填充字符串是构建网络应用程序时的一个常见要求。我们经常需要为字符串应用填充字符,以获得固定的字符串长度。假设在表格列中有一个从 0 开始到 10 结束的数字列表。在这种情况下,我们可以使用前导零填充和一个共享实用程序来改善表格的视觉效果:

function format(num) {
  return num.toString().padStart(2, '0');
}

let arr = new Array(11).fill().map((e, i) => i);

document.write(`<table>
  <tr>
    <th>#</th>
  </tr>
`);
for(let n of arr) {
  document.write(`<tr>
      <td>${format(n)}</td>
    </tr>`);
}
document.write('</table>'); 

在这里,我们使用内置的 padStart() 方法添加前导零填充,而不是用 JavaScript 编写自己的字符串填充算法。上述代码片段渲染的零填充数字如下:

ECMAScript 标准还引入了 padEnd() 方法,用于在特定字符串的末尾添加填充字符,具体如下:

let token = 'TK023550L';
let displayToken = token.substring(0, 5).padEnd(token.length, '*');
console.log(`Token: ${displayToken}`);    // Token: TK023****

高效的字符串处理方法:replaceAll() 和 matchAll()

在 ES2021 之前,开发人员必须使用 Regex 来替换特定字符串段的所有出现位置,因为 replace() 函数只能替换第一个出现位置:

let msg = 'Hello JavaScript, Hello JavaScript';

console.log(msg.replace('JavaScript', 'Js'));  // Hello Js, Hello JavaScript
console.log(msg.replace(/JavaScript/g, 'Js')); // Hello Js, Hello Js

ES2021 引入了 replaceAll() 字符串方法,用于替换特定字符串段的所有出现:

console.log(msg.replaceAll('JavaScript', 'Js'));  // Hello Js, Hello Js

同时,ES2020 版本引入的 matchAll() 方法可以帮助我们使用可迭代协议遍历 Regex 匹配结果。该方法可帮助我们避免传统的 Regex 结果迭代方法,即使用带有 while 循环的 Regex.exec()(请参阅此解释)。

请看下面的代码片段:

let msg = 'AT01 BT023 AB02 AT224';
let matches = msg.matchAll(/\b(([A-Z]{2})([0-9]{2}))\b/g);  

for(let match of matches) {
  console.log(`${match[2]}-${match[3]}`); // AT-01, AB-02
}

上述代码片段使用 matchAll() 方法遍历所有捕获的组。

本文文字及图片出自 JavaScript String Methods That Make Developer’s Life Easier

阅读余下内容
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号