写在前面
之前也没有认真学习过js关于字符的表达方法,这次正好学习补补。
字符的 Unicode 表示法
JavaScript 允许采用\uxxxx
形式表示一个字符,其中xxxx
表示字符的 Unicode 码点。
码点在\u0000
~\uFFFF
之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。
"\uD842\uDFB7"// "?""\u20BB7"// " 7"
上面代码表示,如果直接在\u
后面跟上超过0xFFFF
的数值(比如\u20BB7
),JavaScript会理解成\u20BB+7
。由于\u20BB
是一个不可打印字符,所以只会显示一个空格,后面跟着一个7
。
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符
"\u{20BB7}"// "?""\u{41}\u{42}\u{43}"// "ABC"let hello = 123;hell\u{6F} // 123'\u{1F680}' === '\uD83D\uDE80'// true
大括号表示法与四字节的 UTF-16 编码是等价的。
JavaScript 共有6种方法可以表示一个字符。
'\z' === 'z' // true//这里是8进制'\172' === 'z' // true//这里也是16进制'\x7A' === 'z' // true'\u007A' === 'z' // true'\u{7A}' === 'z' // true
codePointAt()
var s = "?";s.length // 2s.charAt(0) // ''s.charAt(1) // ''s.charCodeAt(0) // 55362s.charCodeAt(1) // 57271
对于那些需要4
个字节储存的字符(Unicode码点大于0xFFFF
的字符),JavaScript会认为它们是两个字符。
汉字“?”(注意,这个字不是“吉祥”的“吉”)的码点是0x20BB7
,UTF-16编码为0xD842 0xDFB7
(十进制为55362 57271
),需要4
个字节储存。对于这种4
个字节的字符,JavaScript不能正确处理,字符串长度会误判为2
,而且charAt
方法无法读取整个字符,charCodeAt
方法只能分别返回前两个字节和后两个字节的值。
ES6提供了codePointAt
方法,能够正确处理4个字节储存的字符,返回一个字符的码点。
let s = '?a';//这里0位置上实际就返回的是?的字符的10进制s.codePointAt(0) // 134071//与charCodeAt一致,返回的是?的后两个字符10进制s.codePointAt(1) // 57271//'a's.codePointAt(2) // 97s.codePointAt(0).toString(16) // "20bb7"s.codePointAt(2).toString(16) // "61"
codePointAt
方法的参数,仍然是不正确的。比如,上面代码中,字符a
在字符串s
的正确位置序号应该是1,但是必须向codePointAt
方法传入2。解决这个问题的一个办法是使用for...of
循环
let s = '?a';for (let ch of s) { console.log(ch.codePointAt(0).toString(16));}
codePointAt
方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。
function is32Bit(c) { return c.codePointAt(0) > 0xFFFF;}is32Bit("?") // trueis32Bit("a") // false
String.fromCodePoint()
String.fromCharCode(0x20BB7)// "ஷ"
String.fromCharCode
不能识别大于0xFFFF
的码点,所以0x20BB7
就发生了溢出,最高位2
被舍弃了,最后返回码点U+0BB7
对应的字符,而不是码点U+20BB7
对应的字符。
ES6提供了String.fromCodePoint
方法,可以识别大于0xFFFF
的字符,弥补了String.fromCharCode
方法的不足。在作用上,正好与codePointAt
方法相反。
String.fromCodePoint(0x20BB7)// "?"String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'// true
上面代码中,如果String.fromCodePoint
方法有多个参数,则它们会被合并成一个字符串返回。
字符串的遍历器接口
使得字符串可以被for...of
循环遍历。
这个遍历器最大的优点是可以识别大于0xFFFF
的码点
for (let codePoint of '?foo') { console.log(codePoint)}// "?"// "f"// "o"// "o"
at()
也是为了识别大于0xFFFF的字符
'abc'.charAt(0) // "a"'?'.charAt(0) // "\uD842"'abc'.at(0) // "a"'?'.at(0) // "?"
normalize()
提供一种方法,不同表示方法统一为同样的形式,这称为 Unicode 正规化。
'\u01D1'.normalize() === '\u004F\u030C'.normalize()// true//Ǒ(\u01D1)//另一种是提供合成符号(combining character),//即原字符与重音符号的合成,两个字符合成一个字符,//O(\u004F)+ˇ(\u030C) => Ǒ(\u004F\u030C)
includes(), startsWith(), endsWith()
JavaScript只有indexOf
方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
- 都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!';s.startsWith('world', 6) // trues.endsWith('Hello', 5) // trues.includes('Hello', 6) // false
repeat()
repeat
方法返回一个新字符串,表示将原字符串重复n
次。
参数规则
字符串转数字
小数取整,负数报错,负0点几算0,NaN算0
padStart(),padEnd()
padStart()
用于头部补全,padEnd()
用于尾部补全
padStart
和padEnd
一共接受两个参数,
第一个参数用来指定字符串的最小长度,
第二个参数是用来补全的字符串。无参数的话则用空格补全
同样,第一个参数会强转为数字,第二个参数会强转为字符串
如果字符串不用补全则保持不变
常用用法
padStart
的常见用途是为数值补全指定位数。下面代码生成10位的数值字符串。
'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"
模板字符串
ps:觉得还是传统更加简单粗暴,易了解
//传统$('#result').append( 'There are ' + basket.count + ' ' + 'items in your basket, ' + '' + basket.onSale + ' are on sale!');//ES6$('#result').append(` There are ${basket.count} items in your basket, ${basket.onSale} are on sale!`);``
用反引号(`)标识
// 普通字符串`In JavaScript '\n' is a line-feed.`// 多行字符串`In JavaScript this is not legal.`console.log(`string text line 1string text line 2`);// 字符串中嵌入变量let name = "Bob", time = "today";`Hello ${name}, how are you ${time}?`
当需要使用`时就需要转义
let greeting = `\`Yo\` World!`;
如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
嵌入变量,需要将变量名写在${}
之中
本质是模板字符串的大括号内部,就是执行JavaScript代码
原先的是拼接字符串,而模板字符串则是执行代码后拼接