JavaScript 文本

161 阅读3分钟

JavaScript中的文本类型是String,表示为字符串。字符串是不可变的有序序列,每个值代表一个Unicode字符,长度属性表示包含的字符数。JavaScript使用基于零的索引,空字符串的长度为0。没有单个字符串元素的专用类型,一个16位值可以用长度为1的字符串表示。

JavaScript字符串使用UTF-16编码,最常见的Unicode字符的码点是16位的,但超出16位的字符使用UTF-16编码为代理对,一个字符可能由一个或两个16位值表示。

字符串操作方法通常操作16位值而不是字符,不会特别处理代理对,也不保证字符串格式正确。在ES6中,字符串是可迭代的,for/of循环或...操作符迭代的是字符而不是16位值。

字符串字面量

在JavaScript中,可以使用单引号(')、双引号(")或反引号(`)来包含字符串。这些字符串字面量可以包含任意字符,包括引号和换行符。下面是一些字符串字面量的例子:

""                  // 空字符串
"testing"
"3.14"
'name="nyforn"'
"Wouldn't you prefer O'Reilly's book?"
"π is the ratio of a circle's circumference to its diameter"
"She said 'hi', he said."

ES6引入了反引号字符串,允许在字符串字面量中插入JavaScript表达式。这种语法称为模板字符串。例如:

const name = "John";
const greeting = `Hello, ${name}!`;
console.log(greeting); // 输出:Hello, John!

在早期版本的JavaScript中,字符串字面量必须写在一行,可以使用 + 操作符将多个字符串连接起来。在ES5中,可以使用反斜杠(\)将字符串字面量写成多行,反斜杠和行终结符不属于字符串字面量的一部分。

const multiLineString = "This is \
a multi-line \
string";
console.log(multiLineString); // 输出:This is a multi-line string


//另外,如果需要在单引号或双引号字符串中包含换行符,可以使用字符序列 \n。
const stringWithNewline = "line1\nline2";
console.log(stringWithNewline);
// 输出:
// line1
// line2

在混合JavaScript和HTML代码时,建议分别使用不同的引号,以避免混淆。例如,在HTML事件处理程序属性中,可以使用双引号,而在JavaScript代码中则使用单引号。

<button onclick="alert('Thank you')">Click Me</button>

需要注意的是,如果在单引号定界的字符串中包含撇号(apostrophe),如 O'Reilly,需要使用反斜杠进行转义,或者在双引号中包含该字符串。

const companyName = 'O'Reilly';
console.log(companyName); // 输出:O'Reilly

字符串字面量中的转义序列

在JavaScript字符串中,反斜杠具有特殊的转义作用,它与后面的字符组合在一起,用来表示一些无法直接表示的字符。例如,\n表示换行符,'表示单引号(或撇号)字符。

下表列出了JavaScript中常见的转义序列及它们表示的字符:

转义序列表示的字符
\0NUL 字符(\u0000)
\b退格符(\u0008)
\t水平制表符(\u0009)
\n换行符(\u000A)
\v垂直制表符(\u000B)
\f进纸符(\u000C)
\r回车符(\u000D)
\ "双引号(\u0022)
\ '单引号或撇号(\u0027)
\ \反斜杠(\u005C)
\xnn由2位十六进制数字nn指定的Unicode字符
\unnnn由4位十六进制数字nnnn指定的Unicode字符
\u{n}由码点n指定的Unicode字符,其中n是介于0和10FFFF之间的1到6位十六进制数字(ES6)

如果字符\位于任何上表以外的字符前面,这个反斜杠当然会被忽略(可能会随版本有新的)。例如#等同于#。

使用字符串

在JavaScript中,字符串的拼接是一种内置特性。使用加号(+)操作符可以将两个字符串连接起来。如果对数值使用 + 操作符,则数值会相加。例如:

let msg = "Hello, " + 'world';
let greeting = "Welcome to my blog, " + "Hello, world" + name;

JavaScript中提供了丰富的API来操作字符串。你可以使用标准的全等(===)和不全等(!==)操作符来比较字符串。字符串比较是通过比较它们的16位值完成的。

要确定一个字符串的长度(即字符串包含的16位值的个数),可以使用字符串的 length 属性

let s = "Hello, world";
s.length; // 返回字符串的长度

除了 length 属性之外,JavaScript还提供了一系列操作字符串的方法:

  • substring(startIndex, endIndex): 返回从 startIndex 到 endIndex (不包括 endIndex)之间的子字符串。
  • slice(startIndex, endIndex): 与 substring 方法类似,但支持负数索引,表示从末尾开始计数。
  • split(separator): 将字符串按照指定的分隔符拆分成数组。
  • indexOf(substring): 返回子字符串第一次出现的位置。
  • lastIndexOf(substring): 返回子字符串最后一次出现的位置。
  • startsWith(prefix): 判断字符串是否以指定的前缀开头。
  • endsWith(suffix): 判断字符串是否以指定的后缀结尾。
  • includes(substring): 判断字符串是否包含指定的子字符串。
  • replace(oldSubstring, newSubstring): 替换字符串中的子字符串。
  • toLowerCase(): 将字符串转换为小写。
  • toUpperCase(): 将字符串转换为大写。
  • normalize(): 将字符串的 Unicode 标准化为 NFC 形式。
  • charAt(index): 返回指定索引处的字符。
  • charCodeAt(index): 返回指定索引处的字符的 Unicode 编码。
  • codePointAt(index): 返回指定索引处字符的 Unicode 码点。

字符串也可以像只读数组一样使用方括号访问单个字符。

let s = "hello, world";
s[0]; // 返回字符串的第一个字符 "h"
s[s.length - 1]; // 返回字符串的最后一个字符 "d"

模版字面量

在ES6及以后的版本中,字符串字面量可以使用反引号(`)来定界。这种语法被称为模板字面量,它可以包含任意JavaScript表达式。模板字面量中的表达式会被求值,并将其值转换为字符串,然后与模板字面量中的文本组合起来。

let name = "Bill";
let greeting = `Hello ${name}`; // greeting == "Hello Bill"

在模板字面量中,位于${}之间的内容被当作JavaScript表达式来解释。而${}之外的部分则是普通的字符串字面量。表达式会被求值,并将其结果插入到模板字面量中。

模板字面量可以包含任意数量的表达式,也可以跨越多行而无需进行特殊的转义。例如:

let errorMessage = `
\u2718 Test failure at ${fileName}:${lineNumber}:
${exception.message}
Stack trace:
${exception.stack}
`;

在这个例子中,第一行末尾的反斜杠(\)转义了第一个换行符,因此最终字符串的第一个字符是Unicode字符✘(\u2718)而不是换行符。

另一个有用的特性是标签化模板字面量。如果在反引号前面有一个函数名(标签),那么模板字面量中的文本和表达式的值将作为参数传递给这个函数。标签函数的返回值就是标签化模板字面量的值。ES6提供了一个内置的标签函数:String.raw()。这个函数返回反引号中未经处理的文本,即不会处理任何反斜杠转义:

let rawString = String.raw`\n`; // 返回未经处理的文本

匹配模式

在JavaScript中,正则表达式(RegExp)是一种用于描述和匹配文本中字符串模式的数据类型。虽然RegExp不是JavaScript的基础类型,但它们有类似于数值和字符串的字面量语法,因此有时候看起来像基础类型。

正则表达式字面量的语法包括一对斜杠(/)之间的文本,第二个斜杠后面可以跟随一个或多个字母,用于修改模式的含义。例如:

/HTML/;        // 匹配字符串中开头的字母HTML
/[1-9][0-9]*/; // 匹配非零数字,后面跟着任意数字
/\bjavascript\b/i; // 匹配单词"javascript",不区分大小写

RegExp对象定义了一些有用的方法,而字符串也有一些接受RegExp参数的方法。例如:

let text = "testing: 1, 2, 3";
let pattern = /\d+/g;     //匹配一个或多个数字
pattern.test(text);       // 返回 true,存在匹配项
text.search(pattern);     // 返回 9,第一个匹配项的位置
text.match(pattern);      // 返回 ["1", "2", "3"],所有匹配项的数组
text.replace(pattern, "#"); // 返回 "testing: #, #, #"
text.split(/\D+/);        // 返回 ["", "1", "2", "3"],基于非数字拆分

上面的例子展示了如何使用正则表达式进行文本匹配、搜索、替换和拆分。正则表达式在JavaScript中是非常强大和常用的工具,可以用于各种文本处理任务。