本篇博客学习摘自阮一峰老师编写的《ECMAScript 6 入门》,记录下做笔记。
学习阶段,如果哪部分有问题,欢迎指正,共同探讨。@Apach3
1.字符的Unicode表示法
JavaScript用\uxxxx
表示一个字符,其中xxxx
为该字符的Unicode码点。这种表示法的码点范围只能在\u0000~\uFFFF
之间,也就是说大于\uFFFF
的字符,必须用两个双字节的形式表示。
显然JavaScript对于字符的表示有时候会出错,ES6对这点进行了改进,将码点放入大括号,就能解决问题。
"\u{20BB7}"
// "��"
"\u{41}\u{42}\u{43}"
// "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80'
// true
上面代码中,最后一个例子表明,大括号表示法与四字节的 UTF-16 编码是等价的。
2.codePointAt()
汉字“��”(注意,这个字不是“吉祥”的“吉”)的码点是0x20BB7
,UTF-16编码为0xD842 0xDFB7
(十进制为55362 57271
),需要4个字节储存。对于这种4个字节的字符,JavaScript不能正确处理,字符串长度会误判为2,而且charAt
方法无法读取整个字符,charCodeAt
方法只能分别返回前两个字节和后两个字节的值。
针对上述问题,ES6提供了codePointAt
方法,能够正确处理4个字节储存的字符,返回一个字符的码点。如下所示:
let s = '��a';
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
上面代码中,codePointAt
方法在第一个字符正确的识别了汉字,第二个字符识别了汉字的后两个字节,第三个字符识别了“a
”。这样不论是两个字节还是四个字节存储的字符,codePointAt
都能正确识别。
codePointAt
方法返回的是码点的十进制值,如果想要十六进制的值,可以使用toString
方法转换一下。
let s = '��a';
for (let ch of s) {
console.log(ch.codePointAt(0).toString(16));
}
// 20bb7
// 61
另外的用途,codePointAt
方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("��") // true
is32Bit("a") // false
3.String.fromCodePoint()
ES5提供String.fromCharCode
方法,用于从码点返回对应字符,但是这个方法不能识别32位的UTF-16字符(Unicode编号大于0xFFFF
)。即String.fromCharCode
不能识别大于0xFFFF
的码点,所以大于0xFFFF
的部分就发生了溢出,高位被舍弃了,最后返回码点U
+未被舍弃的码点对应的字符,而不是原字符。
ES6提供了String.fromCodePoint
方法,可以识别大于0xFFFF
的字符,弥补了String.fromCharCode
方法的不足。在作用上,正好与codePointAt
方法相反。
String.fromCodePoint(0x20BB7)
// "��"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true
上面代码中,如果String.fromCodePoint
方法有多个参数,则它们会被合并成一个字符串返回。
注意,fromCodePoint
方法定义在String
对象上,而codePointAt
方法定义在字符串的实例对象上。
4.字符串的遍历接口
ES6为字符串增加了遍历接口,使得字符串可以被for…of
循环遍历。除了遍历字符串,这个遍历器最大的优点是可以识别大于0xFFFF
的码点,传统的for
循环无法识别这样的码点。
let text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "��"
上面代码中,字符串text
只有一个字符,但是for
循环会认为它包含两个字符(都不可打印),而for...of
循环会正确识别出这一个字符。
5.at()
ES5 对字符串对象提供charAt
方法,返回字符串给定位置的字符。该方法同样不能识别码点大于0xFFFF
的字符。
'abc'.charAt(0) // "a"
'��'.charAt(0) // "\uD842"
上面代码中,charAt
方法返回的是UTF-16编码的第一个字节,实际上是无法显示的。
目前,有一个提案,提出字符串实例的at
方法,可以识别 Unicode 编号大于0xFFFF
的字符,返回正确的字符。
'abc'.at(0) // "a"
'��'.at(0) // "��"
这个方法可以通过垫片库实现。
6.normalize()
Unicode 为了表示许多欧洲语言的语调符号和重音符号,提供了两种方法。一种是直接提供带重音符号的字符,比如Ǒ
(\u01D1
)。另一种是提供合成符号(combining character),即原字符与重音符号的合成,两个字符合成一个字符,比如O
(\u004F
)和ˇ
(\u030C
)合成Ǒ
(\u004F\u030C
)。
这两种表示方法,在视觉和语义上都等价,但是 JavaScript 不能识别。JavaScript会把合成字符视为两个字符,导致表示不相等。
ES6 提供字符串实例的normalize()
方法,用来将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化。
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
// true
normalize
方法可以接受一个参数来指定normalize
的方式,参数的四个可选值如下。
(1)NFC
,默认参数,表示“标准等价合成”(Normalization Form Canonical Composition),返回多个简单字符的合成字符。所谓“标准等价”指的是视觉和语义上的等价。
(2)NFD
,表示“标准等价分解”(Normalization Form Canonical Decomposition),即在标准等价的前提下,返回合成字符分解的多个简单字符。
(3)NFKC
,表示“兼容等价合成”(Normalization Form Compatibility Composition),返回合成字符。所谓“兼容等价”指的是语义上存在等价,但视觉上不等价,比如“囍”和“喜喜”。(这只是用来举例,normalize
方法不能识别中文。)
(4)NFKD
,表示“兼容等价分解”(Normalization Form Compatibility Decomposition),即在兼容等价的前提下,返回合成字符分解的多个简单字符。
'\u004F\u030C'.normalize('NFC').length // 1
'\u004F\u030C'.normalize('NFD').length // 2
上面代码表示,NFC
参数返回字符的合成形式,NFD
参数返回字符的分解形式。
不过,normalize
方法目前不能识别三个或三个以上字符的合成。这种情况下,还是只能使用正则表达式,通过Unicode编号区间判断。
7.includes(), startsWith(), endsWith()
JavaScript中,为了检查字符串是否包含另外一个字符串会用indexOf
方法,ES6又提供了三种新方法:
(1)includes()
:返回布尔值,表示是否找到了参数字符串。
(2)startsWith()
:返回布尔值,表示参数字符串是否在原字符串的头部。
(3)endsWith()
:返回布尔值,表示参数字符串是否在原字符串的尾部。
这三个方法都能带一个或两个参数,如下:
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
其中endsWith
方法会从第二个参数n
开始往前查找,其他方法都是从n
至字符串结束。
8.repeat()
repeat
方法返回一个新字符串,新字符串是原字符串重复几次的结果。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
如果参数是小数,会被取整;参数是负数或Infinity
会被报错;参数是0
到-1
的小数会先被取整,认同为0
;参数为字符串,则会先转为数字。
9.padStart(),padEnd()
padStart
和padEnd
方法提供的功能是在字符串首部或者尾部补全的功能。可以传一或二个参数,传一个参数长度n
,则会默认补全空格;传两个参数n
和补的字符串string
,则会截取补全。
'abc'.padStart(10, '0123456789')
// '0123456abc'
padStart
和padEnd
的功能主要是用于为数值补全指定位数,另一个用途是提示字符串格式。
'12'.padStart(10, '0') // "0000000012"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
10.模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
模板字符串中嵌入变量,需要将变量名写在${}
之中,大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。模板字符串中还能调用函数。
加油!