开发中遇到的小毛病(1)

414 阅读3分钟

使用正则发现的一个小问题

先上代码

let str = 'abcdef'
let reg = /abc/g // 查找所有匹配项
console.log(reg.test(str)) // 输出true
console.log(reg.test(str)) // 输出false

以上代码为一段简单正则验证,验证目标字符串是否包含abc,那为什么连续两次相同的验证却得到不一样的结果呢

导致此问题的重点在于lastIndex属性

语法

RegExpObject.lastIndex

属性说明

该属性存放一个整数,它声明的是上一次匹配文本之后的第一个字符的位置。

上次匹配的结果是由方法 RegExp.exec()RegExp.test() 找到的,它们都以 lastIndex 属性所指的位置作为下次检索的起始点。这样,就可以通过反复调用这两个方法来遍历一个字符串中的所有匹配文本。

该属性是可读可写的。只要目标字符串的下一次搜索开始,就可以对它进行设置。当方法 exec()test() 再也找不到可以匹配的文本时,它们会自动把 lastIndex 属性重置为 0

重要事项:不具有标志 g不表示全局模式RegExp 对象不能使用 lastIndex 属性。

上述对 lastIndex 做出了解释。 简单的说就是,lastIndex 默认是0,每次进行RegExp.test() 或者RegExp.exec() 操作都会对 lastIndex 进行修改。

下面看一段代码

let str = 'abcdefabc'
let reg = /abc/g // 查找所有匹配项
console.log(reg.lastIndex) // 输出 0
console.log(reg.test(str), reg.lastIndex) // 输出true 3
console.log(reg.test(str), reg.lastIndex) // 输出true 9
console.log(reg.test(str), reg.lastIndex) // 输出false 0

从代码可以看出,执行test() 方法的时候,lastIndex 被改变。

并且当第一次匹配到满足条件的部分时,输出true且将 lastIndex 修改为 3

第二次执行 test(),就是从目标字符串的第3个位置开始执行,再次匹配出满足条件的部分时,会输出 true 且再一次修改 lastIndex

当第三次再执行 test() 时,便是从目标字符串的第9个位置开始,没有匹配到对应的满足条件则返回了 true,并且重新修改 lastIndex0

以上我们可以得出结论,test() 会改变 lastIndex,并且每次匹配都是从 目标的第 lastIndex 位置开始。当匹配不到符合条件的部分时,就返回 falselastIndex 重新设置为 0

如何去完善这个小毛病

1、正则中可以 去掉 g ,这样便不会全匹配。

重要事项:不具有标志 g 和不表示全局模式的 RegExp 对象不能使用 lastIndex 属性。

let str = 'abcdef'
let reg = /abc/ // 去掉g修饰符
console.log(reg.lastIndex) // 输出 0
console.log(reg.test(str), reg.lastIndex) // 输出true 0

如上述代码可见,正则中去掉 g 修饰符之后,便不会再影响 lastIndex

2、不去掉 g修饰符,再执行完test() 或者 exec() 之后,对 lastIndex 进行手动赋值。

重要事项: lastIndex 属性是该属性是可读可写的。

let str = 'abcdef'
let reg = /abc/g // 没有去掉g修饰符
console.log(reg.lastIndex) // 输出 0
console.log(reg.test(str), reg.lastIndex) // 输出true 3
reg.lastIndex = 0 // 重新赋值为0
console.log(reg.test(str)) // 输出true

如上述代码可见,在执行一次 test() 之后,手动给 lastIndex 赋值为0, 再执行 test() 时就会输出我们期望得到的 true

如你所见,非~常好用。

以上,结束吧。期待下次