预备知识
- utf-16:把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,Unicode字符的码位,需要1个或2个16位的码元来表示。
- utf-32:使用32个比特对每个Unicode码位进行编码,编码长度是固定的,即32位。
- js内部,字符以utf-16的格式存储,每个字符固定为两个字节。
- String.length的结果不是字符串中字符的个数,而是编码结果字节数/2字节,如果有一个字符的码点超过0xffff,它对length的贡献是2。
ES6对Unicode的支持
1. 字符的Unicode表示法
字符”?”的utf-16编码结果为”D842 DFB7”,utf-32编码结果为”20BB7”,es6对\u20BB7的解读是两个字符,对\u{20BB7}的解读是一个字符,二三两行代码表明 ,大括号表示法和四字节的utf-16编码是等价的。
console.log('\u20BB7')
console.log('\u{20BB7}')
console.log('\uD842\uDFB7')
2.codePointAt()
对于Unicode码点大于0xffff的字符,js会认为它们是两个字符。此时charAt()无法读取整个字符,charCodeAt()分别返回前两个字节和后两个字节的值。
codePointAt(index)能处理4个字节储存的字符,返回10进制的码点。参数index不是字符在字符串中的位置,而是字符相对于字符串的length的位置。可以用toString()方法转换进制。
上面字符串s的编码结果为 D842 DFB7 0061,如果codePonitAt(index)恰好在一个4字节长度字符的起始编码位置,结果能返回4字节的码点,否则会返回低2字节的编码。
for…of循环能正确识别32位的utf-16字符
for (let ch of s) {
console.log(ch.codePointAt(0).toString(16));
}
// 20bb7
// 61
3.String.fromCodePoint()
ES5的String.fromCharCode(code)方法,用于从码点返回对应字符,但是code如果超过0xffff,结果只会对低2个字节进行转换。
ES6的String.fromCodePoint(code)可以识别大于0xffff的码点。
String.fromCharCode(0x20BB7)// "ஷ"
// equal to
String.fromCharCode(0x0BB7)// 只对低2字节进行转换
4.at()
ES5的charAt(index)不能识别码点大于0xffff的字符,ES6的at(index)则可以识别码点大于0xffff的字符。
5.normalize()
许多欧洲语言有语调符号和重音符号。为了表示它们,Unicode 提供了两种方法。一种是直接提供带重音符号的字符,比如Ǒ(\u01D1)。另一种是提供合成符号(combining character),即原字符与重音符号的合成,两个字符合成一个字符,比如O(\u004F)和ˇ(\u030C)合成Ǒ(\u004F\u030C)。
这两种表示方法,在视觉和语义上都等价,但是 JavaScript 不能识别。
'\u01D1'==='\u004F\u030C' //false
'\u01D1'.length // 1
'\u004F\u030C'.length // 2
ES6 提供字符串实例的normalize(parameter)方法(具体参数及其意义,用时补充),用来将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化。
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
// true
6.includes(), startsWith(), endsWith()
传统上js只有indexOf()方法用来确定字符串是否包含在另一个字符串里面。ES6新增下面三个方法。
syntax:
includes(string, index)
startsWith(string, index)
endsWith(string, index)
三种方法的返回值都是布尔值。index指开始搜索位置。
7.repeat()
构造并返回一个新字符串,该字符串包含被连接在一起的指定数量的字符串的副本。指定副本数量如果不是整数,实行上取整。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
'na'.repeat(-0.9) // ""
'na'.repeat(2.9) // "nana"
8.padStart(), padEnd()
syntax:
padStart(len, string)
padEnd(len, string)
len–补全后字符串长度;
string(optional)–用于补全的字符串。缺省时候为空格。
这两个方法都返回一个新新字符串,原字符串无改动。如果len小于等于原字符串长度,则返回原字符串。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
9.模板字符串
用反引号(`)标识,可以当普通字符串使用,也可以定义多行字符串,或者在字符串中嵌入变量。
syntax:
`string text`
`string text line 1
string text line 2`
`string text ${expression} string text`
tag `string text ${expression} string text`
模板字符串中的多行字符串,所有空格、缩进和回车都会被保留。${ }中是表达式,可以是变、引用的对象属性和js表达式(包括函数调用语句)。
11.标签模板(tagged template)
函数名后紧跟着模板字符串,该函数将被调用来处理这个模板字符串。
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);