字符串中的字符有两种,一种是由一个编码单元16位表示的BMP字符,另一种是由两个编码单元32位表示的辅助平面字符
在ES5中,所有字符串的操作都是基于16位编码单元
codePointAt
codePointAt 接受编码单元的位置而非字符位置作为参数,返回与字符串中给定位置对应的码位,即一个整数值
也就是说对于BMP字符集中的字符,codePointAt方法的返回值与charCodeAt方法的相同,而对于非BMP字符集来说返回值则不同
let txt='?a'
console.log(txt.charCodeAt(0))//55362 --仅仅返回位置0处的第一个编码单元
console.log(txt.charCodeAt(1))//57271
console.log(txt.charCodeAt(2))//97
console.log(txt.codePointAt(0))//134071 --返回完整的码位,即使这个码位包含多个编码单元
console.log(txt.codePointAt(1))//57271
console.log(txt.codePointAt(2))//97
检测字符占用编码单元数量
function is32Bit(c) {
return c.codePointAt(0)>0xFFFF
}
console.log(is32Bit('?'))//true
console.log(is32Bit('a'))//false
String.fromCodePoint
codePoint方法在字符串中检索一个字符的码位,也可以使用String.fromCodePoint方法根据指定的码位生成一个字符
可以将String.fromCodePoint看成更完整版本的String.fromCharCode,因为对于BMP中的所有字符,这俩方法执行结果相同,只有传递非BMP的码位作用参数时,二者执行结果才有可能不同
normalize
在对不同字符进行排序或比较时,会存在一种可能它们是等效的
1、规范的等效是指无论从哪个角度来看,两个序列的码位都是没有区别的
2、两个互相兼容的码位序列看起来不同,但是在特定情况下可以被交换使用
切记:在对比字符串前一定要把它们标准化为同一种形式
let values = ["test", "demo", "compare", "sort"]
let normalized = values.map(function (txt) {
return txt.normalize()
})
normalized.sort(function (first, second) {
if (first < second) return -1
else if (first === second) return 0
else return 1
})
或者上述代码也可以这样
let values = ["test", "demo", "compare", "sort"]
values.sort(function (first, second) {
// let firstNormalized = first.normalize(),
// secondNormalized = second.normalize(); //可以写成这种形式也可以写成如下这种形式
let firstNormalized = first.normalize('NFC'),
secondNormalized = second.normalize('NFC');
if (firstNormalized < secondNormalized) return -1
else if (firstNormalized === secondNormalized) return 0
else return 1
})
Unicode标准化形式有如下几种
正则u修饰符
当一个正则表达式使用u修饰符时,它就从编码单元操作切换为字符模式
let txt = '?'
console.log(txt.length)//2
console.log(/^.$/.test(txt))//false
console.log(/^.$/u.test(txt))//true
通过上述特性,可检测字符串真正长度
function codePointLength(txt) {
let result = txt.match(/[\s\S]/gu)
return result ? result.length : 0
}
console.log(codePointLength('abc'))//3
console.log(codePointLength('?ab'))//3
console.log('?ab'.length)//4
检测引擎是否支持u修饰符
function hasRegExpU(params) {
try {
var pattern = new RegExp(".", "u")
return true
} catch (ex) {
return false
}
}
如果你的代码仍然需要运行在老式的JS引擎中,使用修饰符时切记使用RegExp构造函数,这样可以避免发生语法错误,并且你可以有选择的检测和使用u修饰符而不会造成系统异常终止
字符串中的子串识别
includes 在字符串中检测是否包含指定文本
startsWith 在字符串的起始部分是否包含指定文本
endsWith 在字符串的结束部分是否包含指定文本
以上三个方法都接受两个参数:1、要搜索的文本 2、可选 开始搜索的索引值,如果指定的第二个参数则会比这个索引值的位置开始匹配,endsWith则从字符串长度减法这个索引值的位置开始匹配
let msg = 'Hello world!'
console.log(msg.startsWith('Hello'))//true
console.log(msg.endsWith('!'))//true
console.log(msg.includes('o'))//true
console.log(msg.startsWith('o'))//false
console.log(msg.endsWith('world!'))//true
console.log(msg.includes('x'))//false
console.log(msg.startsWith('o', 4))//true--从字符串Hello中的o开始
console.log(msg.endsWith('o', 8))//true--字符串的位置是12减去8之后还余下4
console.log(msg.includes('o', 8))//false--从字符串world中的r开始匹配
indexOf和lastIndexof是寻找子串的位置,并且如果你传一个正则表达式进去的话,它们会将传入的正则表达式转化为字符串并搜索它,而在includes等这三方法中,如果你不是传入字符串而是一个正则表达式则会报错
repeat 接受一个number类型的参数,表示该字符串的重复次数,返回当前字符串重复一定次数后的新字符串
console.log('X'.repeat(5))//XXXXX
正则表达式y修饰符
在字符串开始字符匹配时,它会通知搜索从正则表达式的lastIndex属性开始进行,如果在指定位置未能成功匹配则停止继续匹配
let text = 'hello1 hello2 hello3',
pattern = /hello\d\s?/,
result = pattern.exec(text),
globalPattern = /hello\d\s?/g,
glogbalResult = globalPattern.exec(text),
stickyPattern = /hello\d\s?/y,
stickyResult = stickyPattern.exec(text);
console.log(result[0])//hello1
console.log(glogbalResult[0])//hello1
console.log(stickyResult[0])//hello1
pattern.lastIndex = 1
globalPattern.lastIndex = 1
stickyPattern.lastIndex = 1
result = pattern.exec(text)
glogbalResult = globalPattern.exec(text)
stickyResult = stickyPattern.exec(text)
console.log(result[0])//hello1
console.log(glogbalResult[0])//hello2
console.log(stickyResult[0])//报错
关于修饰符有2点:
1、只有调用exec和test方法才会涉及lastIndex
2、当lastIndex的值为0时,如果正则表达式中含有^则是否使用粘滞正则表达式并无差别,如果lastIndex的值不为0则该表达式永远不会匹配到正确结果
let pattern=/hello\d/y
console.log(pattern.sticky)//true
正则表达式复制
ES5中复制正则表达式只能这样
var re1 = /ab/i,
re2 = new RegExp(re1);
如果想要对re1重新指定修饰符则不行,ES6 增加了这一新功能
var re1 = /ab/i,
re2 = new RegExp(re1, "g")
console.log(re1)// /ab/i
console.log(re2)// /ab/g
console.log(re1.test('ab'))//true
console.log(re2.test('ab'))//true
console.log(re1.test('AB'))//true
console.log(re2.test('AB'))//false
正则中的flags属性
let re=/ab/g
console.log(re.source)// ab
console.log(re.flags)// g --ES新增的属性
模板字面量
在ES6之前多行字符串只能在一个新行最前方添加反斜杠来承接上一行代码
var message='Multiline\
string'
但是这样有一个问题,在控制台输出在了同一行,所以只能通过手工插入n换行符
ES6中通过反撇号来创建多行字符串,在反撇号中所有空白符都属于字符串的一部分,所以千万要小心缩进
字符串占位符可以包含任意的JS表达式,占位符中可访问作用域中所有可访问的变量,尝试嵌入一个未定义的变量总是会抛出错误
let count = 10,
price = 2.5,
message = `${count} items cost $ ${(count * price).toFixed(2)}.`
//10 items cost $ 25.00.
字符串占位符还可以内嵌,内嵌的{后必须包含在反撇号中
let name = 'angela',
message = `Hello,${`
my name is ${name}`
}`
console.log(message)
String.raw访问字符串前的原生字符串
let msg1 = `Multiline\nstirng`,
msg2 = String.raw`Multiline\nstring`
console.log(msg1)//Multiline
//string
console.log(msg2)//Multiline\nstring
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。