字符的 Unicode 表示法
JavaScript 允许采用 \ uxxxx 形式表示一个字符, 其中 "xxxx" 表示字符的码点.
"\u0061" // "a"
但是, 这种表示法只限于 \ u0000--\uFFFF 之间的字符. 超出这个范围的字符, 必须用两个双字节的形式表达.
- "\uD842\uDFB7"
- // ""
- "\u20BB7"
- // "7"
上面代码表示, 如果直接在 \ u 后面跟上超过 0xFFFF 的数值(比如 \ u20BB7),JavaScript 会理解成 \ u20BB+7. 由于 \ u20BB 是一个不可打印字符, 所以只会显示一个空格, 后面跟着一个 7.
ES6 对这一点做出了改进, 只要将码点放入大括号, 就能正确解读该字符.
下面代码中, 最后一个例子表明, 大括号表示法与四字节的 UTF-16 编码是等价的.
- "\u{20BB7}"
- // ""
- "\u{
- 41
- }\u{
- 42
- }\u{
- 43
- }"
- // "ABC"
- let hello = 123;
- hell\u{
- 6F
- } // 123
- '\u{1F680}' === '\uD83D\uDE80'
- // true
有了上述表示法之后, JavaScript 共有 6 种方法可以表示一个字符.
- '\z' === 'z' // true
- '\172' === 'z' // true
- '\x7A' === 'z' // true
- '\u007A' === 'z' // true
- '\u{7A}' === 'z' // true
- codePointAt()
ES6 提供了 codePointAt 方法, 能够正确处理 4 个字节储存的字符, 返回一个字符的码点.
- var s = 'a';
- s.codePointAt(0) // 134071
- s.codePointAt(1) // 57271
- s.codePointAt(2) // 97
codePointAt 方法的参数, 是字符在字符串中的位置 (从 0 开始). 上面代码中, JavaScript 将 "a" 视为三个字符, codePointAt 方法在第一个字符上, 正确地识别了 "", 返回了它的十进制码点 134071(即十六进制的 20BB7). 在第二个字符(即 "" 的后两个字节) 和第三个字符 "a" 上, codePointAt 方法的结果与 charCodeAt 方法相同.
codePointAt 方法返回的是码点的十进制值, 如果想要十六进制的值, 可以使用 toString 方法转换一下.
- var s = 'a';
- s.codePointAt(0).toString(16) // "20bb7"
- s.codePointAt(2).toString(16) // "61"
实际上 codePointAt 方法的参数, 仍然是不正确的. 上面代码中, 字符 a 在字符串 s 的正确位置序号应该是 1, 但是必须向 codePointAt 方法传入 2. 解决这个问题的一个办法是使用 for...of 循环, 因为它会正确识别 32 位的 UTF-16 字符.
- var s = 'a';
- for (let ch of s) {
- console.log(ch.codePointAt(0).toString(16));
- }
- // 20bb7
- // 61
- String.fromCodePoint()
ES5 提供 String.fromCharCode 方法, 用于从码点返回对应字符, 但是这个方法不能识别 32 位的 UTF-16 字符(Unicode 编号大于 0xFFFF).
下面代码中, String.fromCharCode 不能识别大于 0xFFFF 的码点, 所以 0x20BB7 就发生了溢出, 最高位 2 被舍弃了, 最后返回码点 U+0BB7 对应的字符, 而不是码点 U+20BB7 对应的字符.
- String.fromCharCode(0x20BB7)
- // "ஷ"
ES6 提供了 String.fromCodePoint 方法, 可以识别 0xFFFF 的字符, 弥补了 String.fromCharCode 方法的不足. 在作用上, 正好与 codePointAt 方法相反.
- String.fromCodePoint(0x20BB7)
- // ""
- String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
- // true
上面代码中, 如果 String.fromCodePoint 方法有多个参数, 则它们会被合并成一个字符串返回.
注意, fromCodePoint 方法定义在 String 对象上, 而 codePointAt 方法定义在字符串的实例对象上.
字符串的遍历器接口
ES6 为字符串添加了遍历器接口(详见《Iterator》一章), 使得字符串可以被 for...of 循环遍历.
- for (let codePoint of 'foo') {
- console.log(codePoint)
- }
- // "f"
- // "o"
- // "o"
- at()
目前, ES6 有一个提案, 提出字符串实例的 at 方法, 可以识别 Unicode 编号大于 0xFFFF 的字符, 返回正确的字符.
- 'abc'.at(0) // "a"
- ''.at(0) // ""
- normalize()
许多欧洲语言有语调符号和重音符号. 为了表示它们, Unicode 提供了两种方法. 一种是直接提供带重音符号的字符, 比如Ǒ(\u01D1). 另一种是提供合成符号 (combining character), 即原字符与重音符号的合成, 两个字符合成一个字符, 比如 O(\u004F) 和ˇ(\u030C)合成Ǒ(\u004F\u030C).
这两种表示方法, 在视觉和语义上都等价, 但是 JavaScript 不能识别.
- '\u01D1'==='\u004F\u030C' //false
- '\u01D1'.length // 1
- '\u004F\u030C'.length // 2
上面代码表示, JavaScript 将合成字符视为两个字符, 导致两种表示方法不相等.
ES6 提供字符串实例的 normalize()方法, 用来将字符的不同表示方法统一为同样的形式, 这称为 Unicode 正规化.
- '\u01D1'.normalize() === '\u004F\u030C'.normalize()
- // true
normalize 方法可以接受一个参数来指定 normalize 的方式, 参数的四个可选值如下.
NFC, 默认参数, 表示 "标准等价合成"(Normalization Form Canonical Composition), 返回多个简单字符的合成字符. 所谓 "标准等价" 指的是视觉和语义上的等价.
NFD, 表示 "标准等价分解"(Normalization Form Canonical Decomposition), 即在标准等价的前提下, 返回合成字符分解的多个简单字符.
NFKC, 表示 "兼容等价合成"(Normalization Form Compatibility Composition), 返回合成字符. 所谓 "兼容等价" 指的是语义上存在等价, 但视觉上不等价, 比如 "囍" 和 "喜喜".(这只是用来举例, normalize 方法不能识别中文.)
NFKD, 表示 "兼容等价分解"(Normalization Form Compatibility Decomposition), 即在兼容等价的前提下, 返回合成字符分解的多个简单字符.
下面代码表示, NFC 参数返回字符的合成形式, NFD 参数返回字符的分解形式.
不过, normalize 方法目前不能识别三个或三个以上字符的合成. 这种情况下, 还是只能使用正则表达式, 通过 Unicode 编号区间判断.
- '\u004F\u030C'.normalize('NFC').length // 1
- '\u004F\u030C'.normalize('NFD').length // 2
- includes(), startsWith(), endsWith()
传统上, JavaScript 只有 indexOf 方法, 可以用来确定一个字符串是否包含在另一个字符串中. ES6 又提供了三种新方法.
includes(): 返回布尔值, 表示是否找到了参数字符串.
startsWith(): 返回布尔值, 表示参数字符串是否在源字符串的头部.
endsWith(): 返回布尔值, 表示参数字符串是否在源字符串的尾部.
- var s = 'Hello world!';
- s.startsWith('Hello') // true
- s.endsWith('!') // true
- s.includes('o') // true
这三个方法都支持第二个参数, 表示开始搜索的位置.
下面代码表示, 使用第二个参数 n 时, endsWith 的行为与其他两个方法有所不同. 它针对前 n 个字符, 而其他两个方法针对从第 n 个位置直到字符串结束.
- var s = 'Hello world!';
- s.startsWith('world', 6) // true
- s.endsWith('Hello', 5) // true
- s.includes('Hello', 6) // false
- repeat()
repeat 方法返回一个新字符串, 表示将原字符串重复 n 次.
参数如果是小数, 会被取整.
如果 repeat 的参数是负数或者 Infinity, 会报错.
- 'x'.repeat(3) // "xxx"
- 'hello'.repeat(2) // "hellohello"
- 'na'.repeat(0) // ""'na'.repeat(2.9) //"nana"'na'.repeat(Infinity)
- // RangeError
- 'na'.repeat(-1)
- // RangeError
- padStart(),padEnd()
ES7 推出了字符串补全长度的功能. 如果某个字符串不够指定长度, 会在头部或尾部补全. padStart 用于头部补全, padEnd 用于尾部补全.
- 'x'.padStart(5, 'ab') // 'ababx'
- 'x'.padStart(4, 'ab') // 'abax'
- 'x'.padEnd(5, 'ab') // 'xabab'
- 'x'.padEnd(4, 'ab') // 'xaba'
上面代码中, padStart 和 padEnd 一共接受两个参数, 第一个参数用来指定字符串的最小长度, 第二个参数是用来补全的字符串.
模板字符串
模板字符串 (template string) 是增强版的字符串, 用反引号 (`) 标识. 它可以当作普通字符串使用, 也可以用来定义多行字符串, 或者在字符串中嵌入变量.
- $('#result').append(`
- There are <b>${basket.count}</b> items
- in your basket, <em>${basket.onSale}</em>
- are on sale!
- `);
来源: http://www.jianshu.com/p/aedba4728cbb