一、JavaScript中的String类型用于表示文本型的数据。它是由无符号整数值(16bit)作为元素而组成的集合。
二、在 JavaScript 中,文本数据被以字符串形式存储,单个字符没有单独的类型。
三、字符串中的每个元素在字符串中占据一个位置。
1、索引值/index值从0开始。
2、字符串的长度就是字符串中所含的元素个数。
四、字符串的内部格式始终是UTF-16,它不依赖于页面编码。

包含字符串的方式

一、在 JavaScript 中,有三种包含字符串的方式
1、双引号:””
2、单引号:’’
3、反引号:``
【示例1】

  1. let str = "Hello";
  2. let str2 = 'Single quotes are ok too';
  3. let phrase = `can embed another ${str}`;

二、双引号和单引号都是“简单”引用,在 JavaScript 中两者几乎没有什么差别。
二、反引号是功能扩展引号。它们允许我们通过将变量和表达式包装在${…}中,来将它们嵌入到字符串中。
【示例1】

  1. let name = "John";
  2. // 嵌入一个变量
  3. alert( `Hello, ${name}!` ); // Hello, John!
  4. // 嵌入一个表达式
  5. alert( `the result is ${1 + 2}` ); // the result is 3

1、${…}内的表达式会被计算,计算结果会成为字符串的一部分。
2、可以在${…}内放置任何东西:诸如名为name的变量,或者诸如1 + 2的算数表达式,或者其他一些更复杂的。
3、这仅仅在反引号内有效,其他引号不允许这种嵌入。

  1. alert( "the result is ${1 + 2}" ); // the result is ${1 + 2}(使用双引号则不会计算

创建字符串的方式

创建字符串的方式:String字面量值、String对象

String字面量

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

  1. 'foo'
  2. "bar"

二、可以使用转义序列来创建更复杂的字符串
1、16进制转义序列
\x之后的数值将被认为是16进制数

  1. '\xA9' // "©"

2、Unicode转义序列
Unicode转义序列在\u之后需要至少4个字符

  1. '\u00A9' // "©"

3、Unicode字元逸出
(1)这是ECMAScript6中的新特性。
(2)有了Unicode字元逸出,任何字符都可以用16进制数转义,这使得通过Unicode转义表示大于0x10FFFF的字符成为可能。使用简单的Unicode转义时通常需要分别写字符相应的两个部分(大于0x10FFFF的字符需要拆分为相应的两个小于0x10FFFFF的部分)来达到相同的效果。

  1. '\u{2F804}'
  2. // the same with simple Unicode escapes
  3. '\uD87E\uDC04'

String对象 / 字符串对象

见String对象:https://www.yuque.com/tqpuuk/yrrefz/wvo58h

文本格式化

多行模板字符串

一、模板字符串是一种允许内嵌表达式的String字面值。可以用它实现多行字符串或者字符串内插等特性。
二、模板字符串使用反勾号(``)包裹内容而不是单引号或双引号。
三、模板字符串可以包含占位符。占位符用美元符号和花括号标识(${expression})

多行

一、创建多行字符串
1、使用一般字符串时,创建多行的字符串

  1. console.log("string text line 1\n\
  2. string text line 2")
  3. // "string text line 1
  4. // string text line 2"

2、使用模板字符串时,创建多行的字符串

  1. console.log(`string text line 1
  2. string text line 2`)
  3. // "string text line 1
  4. // string text line 2"

嵌入表达式

一、嵌入表达式
1、在一般的字符串中嵌入表达式

  1. const five = 5
  2. const ten = 10
  3. console.log('Fifteen is ' + (five + ten) + ' and not ' + (2 * five + ten) + '.')
  4. // "Fifteen is 15 and not 20"

2、使用模板字符串,可以使用语法糖让类似功能的实现代码更具可读性。

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

国际化

一、Intl对象是ECMAScript国际化API的命名空间,它提供了语言敏感的字符串比较,数字格式化和日期时间格式化功能。

Intl对象的属性

属性 描述
Collator对象的构造函数
NumberFormat对象的构造函数
DateTimeFormat对象的构造函数

定序 Collator

一、Collator对象在字符串比较和排序方面很有用。
【示例1】德语中有两种不同的排序方式,电话本(phonebook)和字典(dictionary)。
电话本排序强调发音,比如在排序前 “ä”, “ö”等被扩展为 “ae”, “oe”等发音。

  1. var names = ["Hochberg", "Hönigswald", "Holzman"];
  2. var germanPhonebook = new Intl.Collator("de-DE-u-co-phonebk");
  3. // as if sorting ["Hochberg", "Hoenigswald", "Holzman"]:
  4. console.log(names.sort(germanPhonebook.compare).join(", "));
  5. // logs "Hochberg, Hönigswald, Holzman"

【示例2】有些德语包含变音,所以在字典中忽略变音进行排序是合理的(除非待排序的单词只有变音部分不同:schon 先于 schön)

  1. var germanDictionary = new Intl.Collator("de-DE-u-co-dict");
  2. // as if sorting ["Hochberg", "Honigswald", "Holzman"]:
  3. console.log(names.sort(germanDictionary.compare).join(", "));
  4. // logs "Hochberg, Holzman, Hönigswald"

数字格式化 NumberFormat

一、NumberFormat对象在数字的格式化方面很有用,比如货币数量值

  1. var gasPrice = new Intl.NumberFormat("en-US",
  2. { style: "currency", currency: "USD",
  3. minimumFractionDigits: 3 });
  4. console.log(gasPrice.format(5.259)); // $5.259
  5. var hanDecimalRMBInChina = new Intl.NumberFormat("zh-CN-u-nu-hanidec",
  6. { style: "currency", currency: "CNY" });
  7. console.log(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五

日期和时间格式化 DateTimeFormat

一、DateTimeFormat对象在日期和时间的格式化方面很有用。
【示例1】把一个日期格式化为美式英语格式(不同时区结果不同)

  1. const msPerDay = 24 * 60 * 60 * 1000;
  2. // July 17, 2014 00:00:00 UTC.
  3. const july172014 = new Date(msPerDay * (44 * 365 + 11 + 197));//2014-1970=44年
  4. //这样创建日期真是醉人。。。还要自己计算天数。。。11是闰年中多出的天数。。。
  5. //197是6×30+16(7月的16天)+3(3个大月)-2(2月少2天)
  6. const options = { year: "2-digit", month: "2-digit", day: "2-digit",
  7. hour: "2-digit", minute: "2-digit", timeZoneName: "short" };
  8. const americanDateTime = new Intl.DateTimeFormat("en-US", options).format;
  9. console.log(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT

正则表达式

见:https://www.yuque.com/tqpuuk/yrrefz/tezl6q

特殊字符

一、可以通过使用“换行符(newline character)”,以支持使用单引号和双引号来创建跨行字符串。
1、换行符写作\n,用来表示换行:

let guestList = "Guests:\n * John\n * Pete\n * Mary";

alert(guestList); // 一个多行的客人列表

2、这两行描述的是一样的,只是书写方式不同:

let str1 = "Hello\nWorld"; // 使用“换行符”创建的两行字符串

// 使用反引号和普通的换行创建的两行字符串
let str2 = `Hello
World`;

alert(str1 == str2); // true

二、其他不常见的“特殊”字符。完整列表:

字符 描述
\n 换行
回车:不单独使用。Windows 文本文件使用两个字符\n的组合来表示换行。
\‘, \“ 引号
\\ 反斜线
\t 制表符
\b, \f, \v 退格,换页,垂直标签 —— 为了兼容性,现在已经不使用了。
\xXX 具有给定十六进制 Unicode XX 的 Unicode 字符,例如:’\x7A’ 和 ‘z’ 相同。
\uXXXX 以 UTF-16 编码的十六进制代码XXXX的 unicode 字符,例如\u00A9——是版权符号©的 unicode。它必须正好是 4 个十六进制数字。
\u{X…XXXXXX}
(1 到 6 个十六进制字符)
具有给定 UTF-32 编码的 unicode 符号。一些罕见的字符用两个 unicode 符号编码,占用 4 个字节。这样我们就可以插入长代码了。

【示例1】unicode 示例:

alert( "\u00A9" ); // ©
alert( "\u{20331}" ); // 佫,罕见的中国象形文字(长 unicode)
alert( "\u{1F60D}" ); // 😍,笑脸符号(另一个长 unicode)

三、所有的特殊字符都以反斜杠字符\开始。它也被称为“转义字符”。
【示例1】如果我们想要在字符串中插入一个引号,我们也会使用它。

alert( 'I\'m the Walrus!' ); // I'm the Walrus!

1、正如你所看到的,我们必须在内部引号前加上反斜杠\’,否则它将表示字符串结束。
2、当然,只有与外部闭合引号相同的引号才需要转义。因此,作为一个更优雅的解决方案,我们可以改用双引号或者反引号:

alert( `I'm the Walrus!` ); // I'm the Walrus!

3、注意反斜杠\在 JavaScript 中用于正确读取字符串,然后消失。内存中的字符串没有\。你从上述示例中的alert可以清楚地看到这一点。
4、但是如果我们需要在字符串中显示一个实际的反斜杠\应该怎么做?
(1)我们可以这样做,只需要将其书写两次\:

alert( `The backslash: \\` ); // The backslash: \

比较字符串

【见】比较运算符#字符串比较:https://www.yuque.com/tqpuuk/yrrefz/wza8dh#nbIY2

内部,Unicode

一、进阶内容:这部分会深入字符串内部。如果你计划处理 emoji、罕见的数学或象形文字或其他罕见的符号,这些知识会对你有用。
二、如果你不打算支持它们,你可以跳过这一部分。

代理对

一、所有常用的字符都是一个 2 字节的代码。大多数欧洲语言,数字甚至大多数象形文字中的字母都有 2 字节的表示形式。
二、但 2 字节只允许 65536 个组合,这对于表示每个可能的符号是不够的。所以稀有的符号被称为“代理对”的一对 2 字节的符号编码。
三、这些符号的长度是2:

alert( '𝒳'.length ); // 2,大写数学符号 X
alert( '😂'.length ); // 2,笑哭表情
alert( '𩷶'.length ); // 2,罕见的中国象形文字

四、注意,代理对在 JavaScript 被创建时并不存在,因此无法被编程语言正确处理!
五、我们实际上在上面的每个字符串中都有一个符号,但length显示长度为2。
六、String.fromCodePoint和str.codePointAt是几种处理代理对的少数方法。它们最近才出现在编程语言中。在它们之前,只有String.fromCharCode和str.charCodeAt。这些方法实际上与fromCodePoint/codePointAt相同,但是不适用于代理对。
七、获取符号可能会非常麻烦,因为代理对被认为是两个字符:

alert( '𝒳'[0] ); // 奇怪的符号……
alert( '𝒳'[1] ); // ……代理对的一块

八、请注意,代理对的各部分没有任何意义。因此,上述示例中的 alert 显示的实际上是垃圾信息。
九、技术角度来说,代理对也是可以通过它们的代码检测到的:如果一个字符的代码在0xd800..0xdbff范围内,那么它是代理对的第一部分。下一个字符(第二部分)必须在0xdc00..0xdfff范围中。这些范围是按照标准专门为代理对保留的。
十、在上述示例中:

// charCodeAt 不理解代理对,所以它给出了代理对的代码
alert( '𝒳'.charCodeAt(0).toString(16) ); // d835,在 0xd800 和 0xdbff 之间
alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3, 在 0xdc00 和 0xdfff 之间

变音符号与规范化

一、在许多语言中,都有一些由基本字符组成的符号,在其上方/下方有一个标记。
【示例1】字母a可以是àáâäãåā的基本字符。最常见的“复合”字符在 UTF-16 表中都有自己的代码。但不是全部,因为可能的组合太多。
二、为了支持任意组合,UTF-16 允许我们使用多个 unicode 字符:基本字符紧跟“装饰”它的一个或多个“标记”字符。
【示例1】如果我们S后跟有特殊的 “dot above” 字符(代码\u0307),则显示 Ṡ。

alert( 'S\u0307' ); // Ṡ

三、如果我们需要在字母上方(或下方)添加额外的标记 —— 没问题,只需要添加必要的标记字符即可。
【示例1】如果我们追加一个字符 “dot below”(代码\u0323),那么我们将得到“S 上面和下面都有点”的字符:Ṩ。
【示例2】

alert( 'S\u0307\u0323' ); // Ṩ

四、这在提供良好灵活性的同时,也存在一个有趣的问题:两个视觉上看起来相同的字符,可以用不同的 unicode 组合表示。
例如:

let s1 = 'S\u0307\u0323'; // Ṩ,S + 上点 + 下点
let s2 = 'S\u0323\u0307'; // Ṩ,S + 下点 + 上点

alert( `s1: ${s1}, s2: ${s2}` );

alert( s1 == s2 ); // false,尽管字符看起来相同

五、为了解决这个问题,有一个 “unicode 规范化”算法,它将每个字符串都转化成单个“通用”格式。
它由str.normalize()实现。

alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true

六、有趣的是,在实际情况下,normalize()实际上将一个由 3 个字符组成的序列合并为一个:\u1e68(S 有两个点)。

alert( "S\u0307\u0323".normalize().length ); // 1

alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true

七、事实上,情况并非总是如此,因为符号Ṩ是“常用”的,所以 UTF-16 创建者把它包含在主表中并给它了对应的代码。
如果你想了解更多关于规范化规则和变体的信息 —— 它们在 Unicode 标准附录中有详细描述:Unicode 规范化形式,但对于大多数实际目的来说,本文的内容就已经足够了。