TOC
ECMAScript 6 简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
字符串的扩展
字符的 Unicode 表示法
- 基本用法:
ES6 加强了对
Unicode
的支持,允许采用\uxxxx
形式表示一个字符,其中xxxx
表示字符的Unicode
码点。 但是,这种表示法只限于码点在\u0000
~\uFFFF
之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。 ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。有了这种表示法之后,JavaScript 共有 6 种方法可以表示一个字符:'\z' === 'z' // true '\172' === 'z' // true '\x7A' === 'z' // true '\u007A' === 'z' // true '\u{7A}' === 'z' // true
字符串的遍历器接口
- 基本用法:
ES6 为字符串添加了遍历器接口
Iterator
,使得字符串可以被for...of
循环遍历。for(let codePoint of 'foo') { console.log(codePoint) } // "f" // "o" // "o" //除了遍历字符串,这个遍历器最大的优点是可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。 let text = String.fromCodePoint(0x20BB7); for (let i of text) { console.log(i); } // "𠮷"
直接输入 U+2028 和 U+2029
- 基本用法:
JavaScript 字符串允许直接输入字符,以及输入字符的转义形式。但是,JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式。
U+005C:反斜杠(reverse solidus) U+000D:回车(carriage return) U+2028:行分隔符(line separator) U+2029:段分隔符(paragraph separator) U+000A:换行符(line feed)
这个规定本身没有问题,麻烦在于 JSON 格式允许字符串里面直接使用
U+2028
(行分隔符)和U+2029
(段分隔符)。这样一来,服务器输出的 JSON 被JSON.parse
解析,就有可能直接报错。const json = '"\u2028"'; JSON.parse(json); // 可能报错
JSON 格式已经冻结(RFC 7159),没法修改了。为了消除这个报错,ES2019 允许 JavaScript 字符串直接输入
U+2028
(行分隔符)和U+2029
(段分隔符)。const PS = eval("'\u2029'");
注意,模板字符串现在就允许直接输入这两个字符。另外,正则表达式依然不允许直接输入这两个字符,这是没有问题的,因为 JSON 本来就不允许直接包含正则表达式。
JSON.stringify() 的改造
- 基本用法:
根据标准,JSON 数据必须是 UTF-8 编码。但是,现在的
JSON.stringify()
方法有可能返回不符合 UTF-8 标准的字符串。 具体来说,UTF-8 标准规定,0xD800
到0xDFFF
之间的码点,不能单独使用,必须配对使用。JSON.stringify()
的问题在于,它可能返回0xD800
到0xDFFF之间
的单个码点。 为了确保返回的是合法的 UTF-8 字符,ES2019 改变了JSON.stringify()
的行为。如果遇到0xD800
到0xDFFF
之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。JSON.stringify('\u{D834}') // ""\\uD834"" JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""
模板字符串
- 基本用法:
模板字符串(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}?`
标签模板
- 基本用法:
模板字符串的功能不仅仅是上面这些,它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为
标签模板
功能(tagged template)。alert`123` // 等同于 alert(123) let a = 5; let b = 10; tag`Hello ${ a + b } world ${ a * b }`; // 等同于 tag(['Hello ', ' world ', ''], 15, 50);
字符串的新增方法
String.fromCodePoint()
-
基本用法: ES5 提供
String.fromCharCode()
方法,用于从 Unicode 码点返回对应字符,但是这个方法不能识别码点大于0xFFFF
的字符。 ES6 提供了String.fromCodePoint()
方法,可以识别大于0xFFFF
的字符,弥补了String.fromCharCode()
方法的不足。ES5: String.fromCharCode(0x20BB7) // "ஷ" 0x20BB7就发生了溢出,最高位2被舍弃了 ES6: String.fromCodePoint(0x20BB7) // "𠮷" String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y' // true
String.raw()
- 基本用法:
ES6 还为原生的
String
对象,提供了一个raw()
方法。该方法返回一个斜杠都被转义的字符串,往往用于模板字符串的处理方法。String.raw()
方法可以作为处理模板字符串的基本方法,它会将所有变量替换,而且对斜杠进行转义,方便下一步作为字符串来使用。String.raw`Hi\n${2+3}!` // 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!" String.raw`Hi\u000A!`; // 实际返回 "Hi\\u000A!",显示的是转义后的结果 "Hi\u000A!"
实例方法
codePointAt()
- 基本用法:
JavaScript 内部,字符以
UTF-16
的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF
的字符),JavaScript 会认为它们是两个字符。对于这种4个字节的字符,JavaScript 不能正确处理,字符串长度会误判为2,而且charAt()
方法无法读取整个字符,charCodeAt()
方法只能分别返回前两个字节和后两个字节的值。 ES6 提供了codePointAt()
方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。var s = "𠮷"; s.length // 2 s.charAt(0) // '' s.charAt(1) // '' s.charCodeAt(0) // 55362 s.charCodeAt(1) // 57271
normalize()
- 基本用法:
许多欧洲语言有语调符号和重音符号。为了表示它们,Unicode 提供了两种方法:
- 一种是直接提供带重音符号的字符,比如Ǒ(
\u01D1
)。 - 另一种是提供合成符号(combining character),即原字符与重音符号的合成,两个字符合成一个字符,比如O(
\u004F
)和ˇ(\u030C
)合成Ǒ(\u004F\u030C
)。 这两种表示方法,在视觉和语义上都等价,但是 JavaScript 不能识别。ES6 提供字符串实例的normalize()
方法,用来将字符的不同表示方法统一为同样的形式,这称为Unicode 正规化
。
ES5: '\u01D1'==='\u004F\u030C' //false '\u01D1'.length // 1 '\u004F\u030C'.length // 2 ES6: '\u01D1'.normalize() === '\u004F\u030C'.normalize() // true
- 一种是直接提供带重音符号的字符,比如Ǒ(
includes(), startsWith(), endsWith()
- 基本用法:
传统上,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!'; //使用第二个参数n时,endsWith的行为与其他两个方法有所不同。 //它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。 s.startsWith('world', 6) // true 从第n个位置直到字符串结束。 s.endsWith('Hello', 5) // true 前n个字符 s.includes('Hello', 6) // false 从第n个位置直到字符串结束。
repeat()
- 基本用法:
repeat(n)
方法返回一个新字符串,表示将原字符串重复n次。'x'.repeat(3) // "xxx" 'hello'.repeat(2) // "hellohello" 'na'.repeat(0) // "" //参数如果是小数,会被取整。 'na'.repeat(2.9) // "nana" //参数是负数或者Infinity,会报错。 'na'.repeat(Infinity) // RangeError 'na'.repeat(-1) // RangeError //如果参数是 0 到-1 之间的小数,则等同于 0,参数`NaN`等同于 0。 'na'.repeat(-0.9) // "" 'na'.repeat(NaN) // "" //参数是字符串,则会先转换成数字。 'na'.repeat('na') // "" 'na'.repeat('3') // "nanana"
padStart(),padEnd()
- 基本用法:
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。
padStart()
用于头部补全,padEnd()
用于尾部补全。//第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。 'x'.padStart(5, 'ab') // 'ababx' 'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(5, 'ab') // 'xabab' 'x'.padEnd(4, 'ab') // 'xaba' //如果省略第二个参数,默认使用空格补全长度。 'x'.padStart(4) // ' x' 'x'.padEnd(4) // 'x ' //如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。 'xxx'.padStart(2, 'ab') // 'xxx' 'xxx'.padEnd(2, 'ab') // 'xxx'
- 用途:
//padStart()的常见用途是为数值补全指定位数。 '1'.padStart(10, '0') // "0000000001" '12'.padStart(10, '0') // "0000000012" '123456'.padStart(10, '0') // "0000123456" //另一个用途是提示字符串格式。 '12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12" '09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
trimStart(),trimEnd()
- 基本用法:
ES2019 对字符串实例新增了
trimStart()
和trimEnd()
这两个方法。它们的行为与trim()
一致,trimStart()
消除字符串头部的空格,trimEnd()
消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。const s = ' abc '; s.trim() // "abc" s.trimStart() // "abc " s.trimEnd() // " abc"
除了空格键,这两个方法对字符串头部(或尾部)的
tab 键
、换行符
等不可见的空白符号也有效。 浏览器还部署了额外的两个方法,trimLeft()
是trimStart()
的别名,trimRight()
是trimEnd()
的别名。
matchAll()
- 基本用法:
matchAll()
方法返回一个正则表达式在当前字符串的所有匹配。
「下次一定」
下次一定
使用微信扫描二维码完成支付