字符串的扩展
字符的 Unicode 表示法
JavaScript 允许采用 \uxxxx 形式表示一个字符,其中 xxxx 表示字符的 Unicode 码点。
但是,这种表示法只限于码点在 \u0000~\uFFFF 之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。
有了这种表示法之后,JavaScript 共有 6 种方法可以表示一个字符。
codePointAt()
JavaScript 内部,字符以 UTF-16 的格式储存,每个字符固定为2个字节。对于2个字节存储的字符,我们可以用 charAt() 和 charCodeAt() 方法查找具体位置的字符。charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数;而 charAt() 返回的是指定位置的字符子串。对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符。
ES6 提供了codePointAt方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。
汉字“𠮷”(注意,这个字不是“吉祥”的“吉”)的码点是 0x20BB7 ,UTF-16 编码为 0xD842 0xDFB7(十进制为 55362 57271),需要4个字节储存。
codePointAt 方法的参数,是字符在字符串中的位置(从 0 开始)。上面代码中,JavaScript 将“𠮷a”视为三个字符,codePointAt 方法在第一个字符上,正确地识别了“𠮷”,返回了它的十进制码点 134071(即十六进制的20BB7)。在第二个字符(即“𠮷”的后两个字节)和第三个字符“a”上,codePointAt 方法的结果与 charCodeAt 方法相同。
总之,codePointAt 方法会正确返回 32 位的 UTF-16 字符的码点。对于那些两个字节储存的常规字符,它的返回结果与 charCodeAt 方法相同。
codePointAt 方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。
String.fromCodePoint()
ES5 提供 String.fromCharCode 方法,用于从码点返回对应字符,但是这个方法不能识别 32 位的 UTF-16 字符(Unicode 编号大于0xFFFF)。为弥补这一方法的不足,ES6 提供了 String.fromCodePoint 方法,可以识别大于 0xFFFF 的字符。在作用上,正好与 codePointAt 方法相反。
上面代码中,如果 String.fromCodePoint 方法有多个参数,则它们会被合并成一个字符串返回。
注意,fromCodePoint 方法定义在 String 对象上,而 codePointAt 方法定义在字符串的实例对象上。
字符串的遍历器接口
ES6 为字符串添加了遍历器接口(Iterator),使得字符串可以被 for…of 循环遍历。
除了遍历字符串,这个遍历器最大的优点是可以识别大于 0xFFFF 的码点,传统的 for 循环无法识别这样的码点。
上面代码中,字符串 text 只有一个字符,但是 for 循环会认为它包含两个字符(都不可打印), for…of 循环会正确识别出这一个字符。
includes(), startsWith(), endsWith()
传统上,JavaScript 只有 indexOf 方法,可以用来确定一个字符串是否包含在另一个字符串中,并返回指定的字符串值在字符串中首次出现的位置。例如:'abc'.indexOf('b', 0) // => 1
第一个参数为需检索的字符串值,第二个参数为在字符串中开始检索的位置,它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。indexOf() 方法对大小写敏感!如果要检索的字符串值没有出现,则该方法返回 -1。
ES6 又提供了三种新方法。
这三个方法都支持第二个参数,表示开始搜索的位置。
上面代码表示,使用第二个参数n时,endsWith 的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。
repeat()
repeat方法返回一个新字符串,将原字符串重复n次。
参数如果是小数,会被取整。
如果 repeat 的参数是负数或者 Infinity ,会报错。
但是,如果参数是 0 到 -1 之间的小数,则等同于 0,这是因为会先进行取整运算。0 到 -1 之间的小数,取整以后等于-0,repeat 视同为 0。
参数 NaN 等同于 0。如果 repeat 的参数是字符串,则会先转换成数字。
padStart(),padEnd()
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart() 用于头部补全,padEnd() 用于尾部补全。
两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。
如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串。
如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串。
如果省略第二个参数,默认使用空格补全长度。
padStart 的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。
另一个用途是提示字符串格式。
matchAll()
matchAll 方法返回一个正则表达式在当前字符串的所有匹配。
模板字符串
模板字符串是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
上面代码中的模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。如图:
上面代码中,所有模板字符串的空格和换行,都是被保留的,比如<ul>
标签前面会有一个换行。如果你不想要这个换行,可以使用 trim 方法消除它。trim() 方法移除字符串两侧的空白字符或其他预定义字符。
模板字符串中嵌入变量,需要将变量名写在${}
之中。
大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
模板字符串之中还能调用函数。
如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的 toString 方法。
如果模板字符串中的变量没有声明,将报错。
由于模板字符串的大括号内部,就是执行 JavaScript 代码,因此如果大括号内部是一个字符串,将会原样输出。
模板字符串甚至还能嵌套。
上面代码中,模板字符串的变量之中,又嵌入了另一个模板字符串,使用方法如下:
如果需要引用模板字符串本身,在需要时执行,可以像下面这样写。
实例:模板编译