es6字符串扩展
1. 字符的 Unicode 表示法
JavaScript 允许采用\uxxxx
形式表示一个字符,其中xxxx
表示字符的 Unicode 码点。
但是,这种表示法只限于码点在\u0000
~\uFFFF
之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。
"\uD842\uDFB7" // "𠮷"
"\u20BB7" // " 7"
上面代码表示,如果直接在\u
后面跟上超过0xFFFF
的数值(比如\u20BB7
),JavaScript 会理解成\u20BB+7
。由于\u20BB
是一个不可打印字符,所以只会显示一个空格,后面跟着一个7
。
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。
"\u{20BB7}" // "𠮷"
let s='𠮷'; console.log('length',s.length); // length 2
2. codePointAt()
JavaScript 内部,字符以 UTF-16 的格式储存,每个字符固定为2
个字节。对于那些需要4
个字节储存的字符(Unicode 码点大于0xFFFF
的字符),JavaScript 会认为它们是两个字符。
ES6 提供了codePointAt
方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。
let s1='𠮷a'; console.log('length',s1.length); //length 3 console.log('code0',s1.codePointAt(0)); //code0 134071 十进制 正确显示了四个字节字符的码点 console.log('code0',s1.codePointAt(0).toString(16)); //code0 20bb7 转化为16进制了 console.log('code1',s1.codePointAt(1)); //code1 57271 console.log('code2',s1.codePointAt(2)); //code2 97
3.String.fromCodePoint()
ES5 提供String.fromCharCode
方法,用于从码点返回对应字符,但是这个方法不能识别 32 位的 UTF-16 字符(Unicode 编号大于0xFFFF
)。
console.log(String.fromCharCode("0x20bb7")); //ஷ
String.fromCharCode
不能识别大于0xFFFF
的码点,所以0x20BB7
就发生了溢出,最高位2
被舍弃了,最后返回码点U+0BB7
对应的字符,而不是码点U+20BB7
对应的字符。
ES6 提供了String.fromCodePoint
方法,可以识别大于0xFFFF
的字符,弥补了String.fromCharCode
方法的不足。在作用上,正好与codePointAt
方法相反。
console.log(String.fromCodePoint("0x20bb7")); //𠮷
{ let str='\u{20bb7}abc'; for(let i=0;i<str.length;i++){ console.log('es5',str[i]); //es5 � // es5 � // es5 a // es5 b // es5 c } for(let code of str){ console.log('es6',code); //es6 𠮷 // es6 a // es6 b // es6 c } }
4. 字符串的遍历器接口
ES6 为字符串添加了遍历器接口,使得字符串可以被for...of
循环遍历。
除了遍历字符串,这个遍历器最大的优点是可以识别大于0xFFFF
的码点,传统的for
循环无法识别这样的码点。
上面3.的例子。
5.includes(), startsWith(), endsWith()
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部
let str="string"; console.log(str.includes("c")); //false console.log(str.startsWith('str')); //true console.log(str.endsWith('ng')); //true
这三个方法都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!'; s.startsWith('world', 6) // true s.endsWith('Hello', 5) // true s.includes('Hello', 6) // false
使用第二个参数n
时,endsWith
的行为与其他两个方法有所不同。它针对前n
个字符,而其他两个方法针对从第n
个位置直到字符串结束。
6.repeat()
repeat
方法返回一个新字符串,表示将原字符串重复n
次。
let str="abc"; console.log(str.repeat(3)); //abcabcabc
参数如果是小数,会被向下取整(正数)
{ let str="ab"; console.log(str.repeat(2.9)); //abab }
参数是负数或者Infinity
,会报错。
但若参数是 0 到-1 之间的小数,则等同于 0,这是因为会先进行取整运算。0 到-1 之间的小数,取整以后等于-0
,repeat
视同为 0。
'ab'.repeat(-0.9) // ""
NaN
等同于 0
'ab'.repeat(NaN) // ""
7.padStart(),padEnd()
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。
{ console.log('1'.padStart(2,'0')); //01 console.log('1'.padEnd(2,'0')); //10 }
padStart作用
为数值补全指定位数。下面代码生成 10 位的数值字符串
'12'.padStart(10, '0') // "0000000012"
提示字符串格式
'5-31'.padStart(10, 'YYYY-MM-DD') // "YYYY-M5-31"
8. 模板字符串
在ES6中,模板字符串中嵌入变量,需要将变量名写在${}
之中,我们可以使用新的语法$ {NAME},并把它放在反引号里:
{ const first="sun"; const last='menghua'; const name=`My name is ${first} ${last}.` ; console.log(name); //My name is sun menghua. }
模板字符串甚至还能嵌套。
{ const tmpl = addrs => ` <table> ${addrs.map(addr => ` <tr><td>${addr.first}</td></tr> <tr><td>${addr.last}</td></tr> `).join('')} </table> `; const data = [ { first: '<Jane>', last: 'Bond' }, { first: 'Lars', last: '<Croft>' }, ]; console.log(tmpl(data)); // <table> // // <tr><td><Jane></td></tr> // <tr><td>Bond</td></tr> // // <tr><td>Lars</td></tr> // <tr><td><Croft></td></tr> // // </table> }
所有模板字符串的空格和换行,都是被保留的.
9.标签模板
模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。
标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
但是,如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
{ let a = 5; let b = 10; function tag(s, v1, v2) { console.log(s); //["Hello ", " world ", "", raw: Array(3)] console.log(s[0]); //Hello console.log(s[1]); // world console.log(s[2]); // (空) console.log(s[3]); //undefined console.log(v1); //15 console.log(v2); //50 return s+v1+v2; } tag`Hello ${ a + b } world ${ a * b}`; //"Hello , world ,1550" }
tag
函数所有参数的实际值如下。
- 第一个参数:
['Hello ', 'world ', '']
- 第二个参数: 15
- 第三个参数:50
-
也就是说,
tag
函数实际上以下面的形式调用。tag(['Hello ', ' world ', ''], 15, 50)
10.String.raw()
ES6 还为原生的 String 对象,提供了一个
raw
方法。String.raw
方法,往往用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串。String.raw`Hi\\n` // "Hi\\\\n" String.raw`Hi\u000A!`; // "Hi\\u000A!"
String.raw
方法也可以作为正常的函数使用。这时,它的第一个参数,应该是一个具有raw
属性的对象,且raw
属性的值应该是一个数组。 -
String.raw({ raw: 'test' }, 0, 1, 2); // 't0e1s2t' String.raw({ raw: 'test' }, 5,'c','y'); // "t5ecsyt"