ES6 增强了对 Unicode 的支持,容许采用\uxxxx
形式表示一个字符,其中xxxx
表示字符的 Unicode 码点。javascript
限于码点在\u0000
~\uFFFF
之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。java
直接在\u
后面跟上超过0xFFFF
的数值会理解错误。git
改进方案,只要将码点放入大括号,就能正确解读该字符github
"\u{20BB7}"
// "𠮷
复制代码
'z' === 'z' // true
'\z' === 'z' // true 122
'\172' === 'z' // true 1*8*8 + 7*8 +2 = 122 // 对应下面的\ddd模式
'\x7A' === 'z' // true 7*16 + 10 // 对应下面的\xhh模式
'\u007A' === 'z' // true // Unicode 表示法
'\u{7A}' === 'z' // true // Unicode 改进后表示法
复制代码
传统的for
循环没法识别大于0xFFFF
的码点,而for...of
能够。正则表达式
for (let i of text) {
console.log(i);
}
// "𠮷"
复制代码
JavaScript 字符串容许直接输入字符,以及输入字符的转义形式。能够直接在字符串里面输入这个汉字,也能够输入它的转义形式\u4e2d
,二者是等价的。json
'中' === '\u4e2d' // true
复制代码
JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式。数组
U+005C:反斜杠(reverse solidus)markdown
U+000D:回车(carriage return)函数
U+2028:行分隔符(line separator)oop
U+2029:段分隔符(paragraph separator)
U+000A:换行符(line feed)
为消除JSON JSON.parse
解析行分隔符与段分隔符的异常,ES2019 容许 JavaScript 字符串直接输入 U+2028(行分隔符)和 U+2029(段分隔符)。
注意,模板字符串如今就容许直接输入这两个字符。另外,正则表达式依然不容许直接输入这两个字符,这是没有问题的,由于 JSON 原本就不容许直接包含正则表达式。
JSON 数据必须是 UTF-8 编码。可是,如今的JSON.stringify()
方法有可能返回不符合 UTF-8 标准的字符串。
为了确保返回的是合法的 UTF-8 字符,ES2019 改变了JSON.stringify()
的行为。若是遇到0xD800
到0xDFFF
之间的单个码点,或者不存在的配对形式,它会返回转义字符串。
例如:仅最后的语句返回 ""𝌆""
JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""
JSON.stringify('\uD834\uDF06')
复制代码
模板字符串(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 表达式,能够进行运算,以及引用对象属性。${}
大括号内部还能调用函数。${}
大括号内部是一个字符串,将会原样输出。模板字符串能够紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
模板字符串默认会将字符串转义(\u
和\x
等),致使没法嵌入其余语言。
ES2018 放松了对标签模板里面的字符串转义的限制。若是遇到不合法的字符串转义,就返回undefined
,而不是报错,而且从raw
属性上面能够获得原始字符串。
对字符串转义的放松,只在标签模板解析字符串时生效,不是标签模板的场合,依然会报错。
let bad = `bad escape sequence: \unicode`; // 报错
复制代码
ES5 提供String.fromCharCode()
方法,用于从 Unicode 码点返回对应字符,可是这个方法不能识别码点大于0xFFFF
的字符。ES6 提供了String.fromCodePoint()
方法,能够识别大于0xFFFF
的字符,弥补了String.fromCharCode()
方法的不足。
String.fromCharCode(0x20BB7)
// "ஷ"
String.fromCodePoint(0x20BB7)
// "𠮷"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true
复制代码
String.fromCodePoint()
方法与下面的codePointAt()
相反。
JavaScript 内部,字符以 UTF-16 的格式储存,每一个字符固定为2
个字节。对于那些须要4
个字节储存的字符(Unicode 码点大于0xFFFF
的字符),JavaScript 会认为它们是两个字符。
var s = "𠮷";
s.length // 2
s.charAt(0) // ''
s.charAt(1) // ''
s.charCodeAt(0) // 55362
s.charCodeAt(1) // 57271
复制代码
根据以上示例发现,对于4 个字节储存的字符,ES5提供的charAt
,charCodeAt
没法返回咱们想要的值。
ES6 提供了codePointAt()
方法,可以正确处理 4 个字节储存的字符,返回一个字符的码点。
let s = '𠮷a';
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
复制代码
可是,codePointAt()
方法的参数,仍然是不正确的。上面代码中,字符a
在字符串s
的正确位置序号应该是 1,可是必须向codePointAt()
方法传入 2。
方法一:使用for...of
循环
let s = '𠮷a';
for (let ch of s) {
console.log(ch.codePointAt(0).toString(16));
}
// 20bb7
// 61
复制代码
方法二:使用扩展运算符(...
)进行展开运算
let arr = [...'𠮷a']; // arr.length === 2
arr.forEach(
ch => console.log(ch.codePointAt(0).toString(16))
);
// 20bb7
// 61
复制代码
function is32Bit(c) {
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("𠮷") // true
is32Bit("a") // false
复制代码
String.raw()
方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,每每用于模板字符串的处理方法。
String.raw`Hi\n${2+3}!`
// 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"
复制代码
函数的形式,它的第一个参数,应该是一个具备raw
属性的对象,且raw
属性的值应该是一个数组,对应模板字符串解析后的值。
`foo${1 + 2}bar`
// 等同于
String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
复制代码
String.raw = function (strings, ...values) {
let output = '';
let index;
for (index = 0; index < values.length; index++) {
output += strings.raw[index] + values[index];
}
output += strings.raw[index]
return output;
}
复制代码
许多欧洲语言有语调符号和重音符号。为了表示它们,Unicode 提供了两种方法。
一种是直接提供带重音符号的字符,好比Ǒ
(\u01D1)。
另外一种是提供合成符号(combining character),即原字符与重音符号的合成,两个字符合成一个字符,好比O
(\u004F)和ˇ
(\u030C)合成Ǒ
(\u004F\u030C)。
这两种表示方法,在视觉和语义上都等价,可是 JavaScript 不能识别。以下,长度不一致并且相等判断为false
。
'\u01D1'==='\u004F\u030C' //false
'\u01D1'.length // 1
'\u004F\u030C'.length // 2
复制代码
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),即在兼容等价的前提下,返回合成字符分解的多个简单字符。
'\u004F\u030C'.normalize('NFC').length // 1
'\u004F\u030C'.normalize('NFD').length // 2
复制代码
normalize
方法目前不能识别三个或三个以上字符的合成。这种状况下,仍是只能使用正则表达式,经过 Unicode 编号区间判断。
ES5 时代,JavaScript 只有indexOf
方法,能够用来肯定一个字符串是否包含在另外一个字符串中。
ES6 提供了三种新方法:
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
复制代码
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true 针对前n个字符,即'Hello'
s.includes('Hello', 6) // false
复制代码
上面代码表示,使用第二个参数n
时,endsWith
的行为与其余两个方法有所不一样。
endsWith
针对前n
个字符,而includes()
, startsWith()
方法针对从第n
个位置直到字符串结束。
repeat
方法返回一个新字符串,表示将原字符串重复n
次。
repeat
的参数是负数或者Infinity
,会报错。NaN
等同于 0。'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
'na'.repeat(2.9) // "nana" --参数会被取整
'na'.repeat(Infinity) // RangeError --报错
'na'.repeat(-1) // RangeError --报错
'na'.repeat(-0.9) // ""
'na'.repeat(NaN) // ""
'na'.repeat('3') // "nanana" --先转换成数字
复制代码
ES2017 引入了字符串补全长度的功能。若是某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。padStart()
和padEnd()
一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'xxx'.padStart(2, 'ab') // 'xxx' --补全不生效,返回原字符串
'xxx'.padEnd(2, 'ab') // 'xxx' --补全不生效,返回原字符串
'abc'.padStart(10, '0123456789') // '0123456abc' --会截去超出位数的补全字符串
'x'.padStart(4) // ' x' --默认使用空格补全长度
复制代码
数值补全指定位数
'1'.padStart(10, '0') // "0000000001"
复制代码
提示字符串格式
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
复制代码
ES2019 对字符串实例新增了trimStart()
和trimEnd()
这两个方法。它们的行为与trim()
一致,trimStart()
消除字符串头部的空格,trimEnd()
消除尾部的空格。
trimLeft()
是trimStart()
的别名,trimRight()
是trimEnd()
的别名(为了兼容)。