文本格式化

本章介绍如何在 JavaScript 中使用字符串和文本。

字符串

JavaScript 的 字符串 类型用于表示文本数据。它是一组 16 位无符号整数 (UTF-16 代码单元) 的“元素”。字符串中的每个元素都在字符串中占据一个位置。第一个元素位于索引 0,下一个位于索引 1,依此类推。字符串的长度是字符串中元素的数量。您可以使用字符串字面量或字符串对象创建字符串。

字符串字面量

您可以使用单引号或双引号创建简单的字符串

js
'foo'
"bar"

可以使用转义序列创建更高级的字符串

十六进制转义序列

\x 之后的数字被解释为 十六进制 数字。

js
"\xA9" // "©"

Unicode 转义序列

Unicode 转义序列要求 \u 后至少有四个十六进制数字。

js
"\u00A9" // "©"

Unicode 代码点转义

使用 Unicode 代码点转义,任何字符都可以使用十六进制数字转义,以便可以使用高达 0x10FFFF 的 Unicode 代码点。使用简单的 Unicode 转义,通常需要分别写入代理对的一半才能获得相同的结果。

另请参见 String.fromCodePoint()String.prototype.codePointAt()

js
"\u{2F804}"

// the same with simple Unicode escapes
"\uD87E\uDC04"

字符串对象

String 对象是字符串原始数据类型的包装器。

js
const foo = new String("foo"); // Creates a String object
console.log(foo); // [String: 'foo']
typeof foo; // 'object'

您可以对字符串字面量值调用 String 对象的任何方法 - JavaScript 会自动将字符串字面量转换为临时 String 对象,调用该方法,然后丢弃临时 String 对象。您还可以使用字符串字面量的 length 属性。

除非您明确需要使用 String 对象,否则您应该使用字符串字面量,因为 String 对象可能具有反直觉的行为。例如

js
const firstString = "2 + 2"; // Creates a string literal value
const secondString = new String("2 + 2"); // Creates a String object
eval(firstString); // Returns the number 4
eval(secondString); // Returns a String object containing "2 + 2"

String 对象有一个属性 length,它指示字符串中的 UTF-16 代码单元数量。例如,以下代码将 helloLength 赋值为 13,因为 "Hello, World!" 有 13 个字符,每个字符都由一个 UTF-16 代码单元表示。您可以使用数组括号样式访问每个代码单元。您不能更改单个字符,因为字符串是不可变的类数组对象

js
const hello = "Hello, World!";
const helloLength = hello.length;
hello[0] = "L"; // This has no effect, because strings are immutable
hello[0]; // This returns "H"

Unicode 标量值大于 U+FFFF(例如一些罕见的中文/日文/韩文/越南语字符和一些表情符号)的字符在 UTF-16 中使用两个代理代码单元存储。例如,包含单个字符 U+1F600 "Emoji grinning face" 的字符串将具有长度 2。使用方括号访问此类字符串中的单个代码单元可能会产生不希望有的结果,例如形成包含不匹配的代理代码单元的字符串,违反了 Unicode 标准。(示例应在修复 MDN 错误 857438 后添加到此页面。)另请参见 String.fromCodePoint()String.prototype.codePointAt()

String 对象具有多种方法:例如,那些返回字符串本身变体的方法,例如 substringtoUpperCase

下表总结了 String 对象的方法。

String 的方法

方法 描述
charAt(), charCodeAt(), codePointAt() 返回字符串中指定位置的字符或字符代码。
indexOf(), lastIndexOf() 分别返回字符串中指定子字符串的位置或指定子字符串的最后一个位置。
startsWith(), endsWith(), includes() 返回字符串是否以指定字符串开头、结尾或包含指定字符串。
concat() 组合两个字符串的文本并返回一个新字符串。
split() 通过将字符串分割为子字符串,将 String 对象分割成字符串数组。
slice() 提取字符串的一部分并返回一个新字符串。
substring(), substr() 返回字符串的指定子集,可以通过指定开始和结束索引或开始索引和长度来实现。
match(), matchAll(), replace(), replaceAll(), search() 使用正则表达式。
toLowerCase(), toUpperCase()

分别返回字符串的所有小写或所有大写。

normalize() 返回调用字符串值的 Unicode 规范化形式。
repeat() 返回一个字符串,该字符串由对象的元素重复给定次数组成。
trim() 从字符串的开头和结尾修剪空格。

多行模板字面量

模板字面量 是字符串字面量,允许嵌入表达式。您可以使用多行字符串和字符串插值功能。

模板字面量用反引号 (`) 字符而不是双引号或单引号括起来。模板字面量可以包含占位符。这些由美元符号和花括号 (${expression}) 表示。

多行

源代码中插入的任何换行符都是模板字面量的一部分。使用普通字符串,您需要使用以下语法才能获得多行字符串

js
console.log(
  "string text line 1\n\
string text line 2",
);
// "string text line 1
// string text line 2"

要使用多行字符串获得相同的效果,您现在可以编写

js
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"

嵌入表达式

为了在普通字符串中嵌入表达式,您将使用以下语法

js
const five = 5;
const ten = 10;
console.log(
  "Fifteen is " + (five + ten) + " and not " + (2 * five + ten) + ".",
);
// "Fifteen is 15 and not 20."

现在,使用模板字面量,您可以利用语法糖,使这种替换更易读

js
const five = 5;
const ten = 10;
console.log(`Fifteen is ${five + ten} and not ${2 * five + ten}.`);
// "Fifteen is 15 and not 20."

有关更多信息,请阅读 模板字面量 的内容,位于 JavaScript 参考 中。

国际化

Intl 对象是 ECMAScript 国际化 API 的命名空间,它提供语言敏感的字符串比较、数字格式化以及日期和时间格式化功能。Intl.CollatorIntl.NumberFormatIntl.DateTimeFormat 对象的构造函数是 Intl 对象的属性。

日期和时间格式化

Intl.DateTimeFormat 对象可用于格式化日期和时间。以下代码示例将日期格式化为美国英语格式。(结果在其他时区可能不同。)

js
// July 17, 2014 00:00:00 UTC:
const july172014 = new Date("2014-07-17");

const options = {
  year: "2-digit",
  month: "2-digit",
  day: "2-digit",
  hour: "2-digit",
  minute: "2-digit",
  timeZoneName: "short",
};
const americanDateTime = new Intl.DateTimeFormat("en-US", options).format;

// Local timezone vary depending on your settings
// In CEST, logs: 07/17/14, 02:00 AM GMT+2
// In PDT, logs: 07/16/14, 05:00 PM GMT-7
console.log(americanDateTime(july172014));

数字格式化

Intl.NumberFormat 对象可用于格式化数字,例如货币。

js
const gasPrice = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  minimumFractionDigits: 3,
});

console.log(gasPrice.format(5.259)); // $5.259

const hanDecimalRMBInChina = new Intl.NumberFormat("zh-CN-u-nu-hanidec", {
  style: "currency",
  currency: "CNY",
});

console.log(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五

排序

Intl.Collator 对象可用于比较和排序字符串。

例如,德语实际上有两种不同的排序顺序,即电话簿排序和字典排序。电话簿排序强调发音,就像在排序之前将“ä”、“ö”等扩展为“ae”、“oe”等一样。

js
const names = ["Hochberg", "Hönigswald", "Holzman"];

const germanPhonebook = new Intl.Collator("de-DE-u-co-phonebk");

// as if sorting ["Hochberg", "Hoenigswald", "Holzman"]:
console.log(names.sort(germanPhonebook.compare).join(", "));
// "Hochberg, Hönigswald, Holzman"

一些德语单词在词尾添加变音符号,因此在字典中,忽略变音符号进行排序是合理的(除非排序的单词由变音符号区分:schonschön 之前)。

js
const germanDictionary = new Intl.Collator("de-DE-u-co-dict");

// as if sorting ["Hochberg", "Honigswald", "Holzman"]:
console.log(names.sort(germanDictionary.compare).join(", "));
// "Hochberg, Holzman, Hönigswald"

有关 Intl API 的更多信息,请参阅 Introducing the JavaScript Internationalization API